Repository: osmosis-labs/osmosis
Pull request #5173 (2023-05-12 23:53:45)

fix: duplicate price for multiple ticks
<!-- < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < ☺
v                               ✰  Thanks for creating a PR! ✰    
v    Before smashing the submit button please review the checkboxes.
v    If a checkbox is n/a - please still include it but + a little note why
v    If your PR doesn't close an issue, that's OK!  Just remove the Closes: #XXX line!
☺ > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > >  -->

Closes: #XXX

## What is the purpose of the change

Our CL tick logic works off of a precision of 10^-18. This, combined with the fact that our per-tick precision increases at every factor of 10, means that we can have multiple ticks that correlate to the same spot price. For instance. tick -161795100 (along with many other ticks around it) correlates to a spot price of 0.000000000000000002. We need a method to determine what the largest tick (rounding up) is that corresponds to a given spot price and only use that tick (kind of like setting a canonical tick) when referencing this price.

Changes:
- When creating a position, the provided ticks are checked to see if there is a larger tick (rounding up) that represents that price with the same level of precision. If so, that tick is changed to that value
  - Example: the lower tick -161795100 correlates to price 0.000000000000000002. The tick is checked, and a larger tick (-161000000) represents that same price. The lower tick is changed to -161000000.
- `TickToSqrtPrice` now also returns the price as well
  - This is to prevent losing precision when squaring the square root price 
- `CreatePosition` now returns the lowerTick and upperTick in the response 
- Update README

## Testing and Verifying

- Added `TestRoundTick`
- Expand `TestCreatePosition`and `TestInverseRelation_CreatePosition_WithdrawPosition`

## Documentation and Release Note

  - [ ] Does this pull request introduce a new feature or user-facing behavior changes?
  - [ ] Changelog entry added to `Unreleased` section of `CHANGELOG.md`?

Where is the change documented? 
  - [x] Specification (`x/{module}/README.md`)
  - [ ] Osmosis documentation site
  - [x] Code comments?
  - [ ] N/A

p0mvn: Can we get this in ASAP please so that I can merge https://github.com/osmosis-labs/osmosis/pull/5170?
czarcas7ic: @p0mvn yeah ill address these rn

Patch:
diff --git a/.github/workflows/check-broken-links.yml b/.github/workflows/check-broken-links.yml
index ecb5f74e7..10a5165aa 100644
--- a/.github/workflows/check-broken-links.yml
+++ b/.github/workflows/check-broken-links.yml
@@ -13,7 +13,7 @@ jobs:
 
       - name: Link Checker
         id: lychee
-        uses: lycheeverse/lychee-action@v1.8.0
+        uses: lycheeverse/lychee-action@v1.7.0
         with:
           args: --exclude-loopback --verbose --no-progress './**/*.md' './**/*.html'
         env:
diff --git a/osmomath/decimal.go b/osmomath/decimal.go
index 1b8e21ce0..03b6fea77 100644
--- a/osmomath/decimal.go
+++ b/osmomath/decimal.go
@@ -887,16 +887,12 @@ func MaxDec(d1, d2 BigDec) BigDec {
 
 // DecEq returns true if two given decimals are equal.
 // Intended to be used with require/assert:  require.True(t, DecEq(...))
-//
-//nolint:thelper
 func DecEq(t *testing.T, exp, got BigDec) (*testing.T, bool, string, string, string) {
 	return t, exp.Equal(got), "expected:\t%v\ngot:\t\t%v", exp.String(), got.String()
 }
 
 // DecApproxEq returns true if the differences between two given decimals are smaller than the tolerance range.
 // Intended to be used with require/assert:  require.True(t, DecEq(...))
-//
-//nolint:thelper
 func DecApproxEq(t *testing.T, d1 BigDec, d2 BigDec, tol BigDec) (*testing.T, bool, string, string, string) {
 	diff := d1.Sub(d2).Abs()
 	return t, diff.LTE(tol), "expected |d1 - d2| <:\t%v\ngot |d1 - d2| = \t\t%v", tol.String(), diff.String()
diff --git a/osmomath/int.go b/osmomath/int.go
index 6b2fe8002..c3ae4ef28 100644
--- a/osmomath/int.go
+++ b/osmomath/int.go
@@ -435,8 +435,6 @@ func (i BigInt) MarshalAmino() ([]byte, error)   { return i.Marshal() }
 func (i *BigInt) UnmarshalAmino(bz []byte) error { return i.Unmarshal(bz) }
 
 // intended to be used with require/assert:  require.True(IntEq(...))
-//
-//nolint:thelper
 func IntEq(t *testing.T, exp, got BigInt) (*testing.T, bool, string, string, string) {
 	return t, exp.Equal(got), "expected:\t%v\ngot:\t\t%v", exp.String(), got.String()
 }
diff --git a/osmoutils/accum/prefix.go b/osmoutils/accum/prefix.go
index c207d215b..4dea6af88 100644
--- a/osmoutils/accum/prefix.go
+++ b/osmoutils/accum/prefix.go
@@ -8,16 +8,23 @@ const (
 	positionPrefix    = "pos"
 )
 
+// formatAccumPrefix returns the key prefix used for any
+// accum module values to be stored in the KVStore.
+// Returns "accum/{key}" as bytes.
+func formatModulePrefixKey(key string) []byte {
+	return []byte(fmt.Sprintf("%s/%s", modulePrefix, key))
+}
+
 // formatAccumPrefix returns the key prefix used
 // specifically for accumulator values in the KVStore.
 // Returns "accum/acc/{name}" as bytes.
 func formatAccumPrefixKey(name string) []byte {
-	return []byte(fmt.Sprintf(modulePrefix+"/"+accumulatorPrefix+"/%s", name))
+	return formatModulePrefixKey(fmt.Sprintf("%s/%s", accumulatorPrefix, name))
 }
 
 // FormatPositionPrefixKey returns the key prefix used
 // specifically for position values in the KVStore.
-// Returns "accum/acc/pos/{accumName}/{name}" as bytes.
+// Returns "accum/pos/{accumName}/{name}" as bytes.
 func FormatPositionPrefixKey(accumName, name string) []byte {
-	return []byte(fmt.Sprintf(modulePrefix+"/"+accumulatorPrefix+"/"+positionPrefix+"/%s/%s", accumName, name))
+	return formatAccumPrefixKey(fmt.Sprintf("%s/%s/%s", positionPrefix, accumName, name))
 }
diff --git a/proto/osmosis/concentrated-liquidity/tx.proto b/proto/osmosis/concentrated-liquidity/tx.proto
index 1f36da41f..217961db2 100644
--- a/proto/osmosis/concentrated-liquidity/tx.proto
+++ b/proto/osmosis/concentrated-liquidity/tx.proto
@@ -69,6 +69,12 @@ message MsgCreatePositionResponse {
     (gogoproto.moretags) = "yaml:\"liquidity_created\"",
     (gogoproto.nullable) = false
   ];
+  // the lower and upper tick are in the response because there are
+  // instances in which multiple ticks represent the same price, so
+  // we may move their provided tick to the canonical tick that represents
+  // the same price.
+  int64 lower_tick = 6 [ (gogoproto.moretags) = "yaml:\"lower_tick\"" ];
+  int64 upper_tick = 7 [ (gogoproto.moretags) = "yaml:\"upper_tick\"" ];
 }
 
 // ===================== MsgAddToPosition
diff --git a/proto/osmosis/superfluid/tx.proto b/proto/osmosis/superfluid/tx.proto
index 26375d43f..a30df7a52 100644
--- a/proto/osmosis/superfluid/tx.proto
+++ b/proto/osmosis/superfluid/tx.proto
@@ -150,9 +150,8 @@ message MsgUnlockAndMigrateSharesToFullRangeConcentratedPosition {
   ];
   // token_out_mins indicates minimum token to exit Balancer pool with.
   repeated cosmos.base.v1beta1.Coin token_out_mins = 4 [
-    (gogoproto.moretags) = "yaml:\"token_out_mins\"",
-    (gogoproto.nullable) = false,
-    (gogoproto.castrepeated) = "github.com/cosmos/cosmos-sdk/types.Coins"
+    (gogoproto.moretags) = "yaml:\"token_out_min_amounts\"",
+    (gogoproto.nullable) = false
   ];
 }
 
diff --git a/x/concentrated-liquidity/README.md b/x/concentrated-liquidity/README.md
index aba9414ad..57de9236d 100644
--- a/x/concentrated-liquidity/README.md
+++ b/x/concentrated-liquidity/README.md
@@ -284,6 +284,15 @@ a) Preventing trade at a desirable spot price or
 b) Having the front end round the tick's actual price to the nearest
   human readable/desirable spot price
 
+One side effect of increasing precision as we get closer to the minimum tick
+is that multiple ticks can represent the same price. For example, tick
+-161795100 (along with the ticks surrounding it) correlate to a price
+of 0.000000000000000002. To get around any issues this may cause, when a
+position is created with a user defined lower and upper tick, we determine
+if a larger tick exists that represents the same price. If so, we use that tick
+instead of the user defined tick. In the above example, the tick would be
+changed to -161000000, which is the first tick that represents the same price.
+
 ## Concentrated Liquidity Module Messages
 
 ### `MsgCreatePosition`
diff --git a/x/concentrated-liquidity/export_internal.go b/x/concentrated-liquidity/export_internal.go
index 669464fb0..4eb7cb713 100644
--- a/x/concentrated-liquidity/export_internal.go
+++ b/x/concentrated-liquidity/export_internal.go
@@ -6,6 +6,6 @@ import (
 	"github.com/osmosis-labs/osmosis/v15/x/concentrated-liquidity/math"
 )
 
-func TickToSqrtPrice(tickIndex sdk.Int) (price sdk.Dec, err error) {
+func TickToSqrtPrice(tickIndex sdk.Int) (price sdk.Dec, sqrtPrice sdk.Dec, err error) {
 	return math.TickToSqrtPrice(tickIndex)
 }
diff --git a/x/concentrated-liquidity/lp.go b/x/concentrated-liquidity/lp.go
index 9ba93126a..1237f3890 100644
--- a/x/concentrated-liquidity/lp.go
+++ b/x/concentrated-liquidity/lp.go
@@ -31,79 +31,85 @@ const noUnderlyingLockId = uint64(0)
 // - the liquidity delta is zero
 // - the amount0 or amount1 returned from the position update is less than the given minimums
 // - the pool or user does not have enough tokens to satisfy the requested amount
-func (k Keeper) createPosition(ctx sdk.Context, poolId uint64, owner sdk.AccAddress, tokensProvided sdk.Coins, amount0Min, amount1Min sdk.Int, lowerTick, upperTick int64) (uint64, sdk.Int, sdk.Int, sdk.Dec, time.Time, error) {
+func (k Keeper) createPosition(ctx sdk.Context, poolId uint64, owner sdk.AccAddress, tokensProvided sdk.Coins, amount0Min, amount1Min sdk.Int, lowerTick, upperTick int64) (positionId uint64, actualAmount0 sdk.Int, actualAmount1 sdk.Int, liquidityDelta sdk.Dec, joinTime time.Time, lowerTickResult int64, upperTickResult int64, err error) {
 	// Use the current blockTime as the position's join time.
-	joinTime := ctx.BlockTime()
+	joinTime = ctx.BlockTime()
 
 	// Retrieve the pool associated with the given pool ID.
 	pool, err := k.getPoolById(ctx, poolId)
 	if err != nil {
-		return 0, sdk.Int{}, sdk.Int{}, sdk.Dec{}, time.Time{}, err
+		return 0, sdk.Int{}, sdk.Int{}, sdk.Dec{}, time.Time{}, 0, 0, err
 	}
 
 	// Check if the provided tick range is valid according to the pool's tick spacing and module parameters.
 	if err := validateTickRangeIsValid(pool.GetTickSpacing(), lowerTick, upperTick); err != nil {
-		return 0, sdk.Int{}, sdk.Int{}, sdk.Dec{}, time.Time{}, err
+		return 0, sdk.Int{}, sdk.Int{}, sdk.Dec{}, time.Time{}, 0, 0, err
 	}
 	amount0Desired := tokensProvided.AmountOf(pool.GetToken0())
 	amount1Desired := tokensProvided.AmountOf(pool.GetToken1())
 	if amount0Desired.IsZero() && amount1Desired.IsZero() {
-		return 0, sdk.Int{}, sdk.Int{}, sdk.Dec{}, time.Time{}, errors.New("cannot create a position with zero amounts of both pool tokens")
+		return 0, sdk.Int{}, sdk.Int{}, sdk.Dec{}, time.Time{}, 0, 0, errors.New("cannot create a position with zero amounts of both pool tokens")
 	}
 
 	// sanity check that both given minimum accounts are not negative amounts.
 	if amount0Min.IsNegative() {
-		return 0, sdk.Int{}, sdk.Int{}, sdk.Dec{}, time.Time{}, types.NotPositiveRequireAmountError{Amount: amount0Min.String()}
+		return 0, sdk.Int{}, sdk.Int{}, sdk.Dec{}, time.Time{}, 0, 0, types.NotPositiveRequireAmountError{Amount: amount0Min.String()}
 	}
 	if amount1Min.IsNegative() {
-		return 0, sdk.Int{}, sdk.Int{}, sdk.Dec{}, time.Time{}, types.NotPositiveRequireAmountError{Amount: amount1Min.String()}
+		return 0, sdk.Int{}, sdk.Int{}, sdk.Dec{}, time.Time{}, 0, 0, types.NotPositiveRequireAmountError{Amount: amount1Min.String()}
 	}
 
 	// Transform the provided ticks into their corresponding sqrtPrices.
-	sqrtPriceLowerTick, sqrtPriceUpperTick, err := math.TicksToSqrtPrice(lowerTick, upperTick)
+	priceLowerTick, priceUpperTick, sqrtPriceLowerTick, sqrtPriceUpperTick, err := math.TicksToSqrtPrice(lowerTick, upperTick)
 	if err != nil {
-		return 0, sdk.Int{}, sdk.Int{}, sdk.Dec{}, time.Time{}, err
+		return 0, sdk.Int{}, sdk.Int{}, sdk.Dec{}, time.Time{}, 0, 0, err
 	}
 
-	positionId := k.getNextPositionIdAndIncrement(ctx)
+	// If multiple ticks can represent the same spot price, ensure we are using the largest of those ticks.
+	lowerTick, upperTick, err = roundTickToCanonicalPriceTick(lowerTick, upperTick, priceLowerTick, priceUpperTick, pool.GetTickSpacing())
+	if err != nil {
+		return 0, sdk.Int{}, sdk.Int{}, sdk.Dec{}, time.Time{}, 0, 0, err
+	}
+
+	positionId = k.getNextPositionIdAndIncrement(ctx)
 
 	// If this is the first position created in this pool, ensure that the position includes both asset0 and asset1
 	// in order to assign an initial spot price.
 	hasPositions, err := k.HasAnyPositionForPool(ctx, poolId)
 	if err != nil {
-		return 0, sdk.Int{}, sdk.Int{}, sdk.Dec{}, time.Time{}, err
+		return 0, sdk.Int{}, sdk.Int{}, sdk.Dec{}, time.Time{}, 0, 0, err
 	}
 	if !hasPositions {
 		err := k.initializeInitialPositionForPool(ctx, pool, amount0Desired, amount1Desired)
 		if err != nil {
-			return 0, sdk.Int{}, sdk.Int{}, sdk.Dec{}, time.Time{}, err
+			return 0, sdk.Int{}, sdk.Int{}, sdk.Dec{}, time.Time{}, 0, 0, err
 		}
 	}
 
 	// Calculate the amount of liquidity that will be added to the pool when this position is created.
-	liquidityDelta := math.GetLiquidityFromAmounts(pool.GetCurrentSqrtPrice(), sqrtPriceLowerTick, sqrtPriceUpperTick, amount0Desired, amount1Desired)
+	liquidityDelta = math.GetLiquidityFromAmounts(pool.GetCurrentSqrtPrice(), sqrtPriceLowerTick, sqrtPriceUpperTick, amount0Desired, amount1Desired)
 	if liquidityDelta.IsZero() {
-		return 0, sdk.Int{}, sdk.Int{}, sdk.Dec{}, time.Time{}, errors.New("liquidityDelta calculated equals zero")
+		return 0, sdk.Int{}, sdk.Int{}, sdk.Dec{}, time.Time{}, 0, 0, errors.New("liquidityDelta calculated equals zero")
 	}
 
 	// Initialize / update the position in the pool based on the provided tick range and liquidity delta.
-	actualAmount0, actualAmount1, err := k.UpdatePosition(ctx, poolId, owner, lowerTick, upperTick, liquidityDelta, joinTime, positionId)
+	actualAmount0, actualAmount1, err = k.UpdatePosition(ctx, poolId, owner, lowerTick, upperTick, liquidityDelta, joinTime, positionId)
 	if err != nil {
-		return 0, sdk.Int{}, sdk.Int{}, sdk.Dec{}, time.Time{}, err
+		return 0, sdk.Int{}, sdk.Int{}, sdk.Dec{}, time.Time{}, 0, 0, err
 	}
 
 	// Check if the actual amounts of tokens 0 and 1 are greater than or equal to the given minimum amounts.
 	if actualAmount0.LT(amount0Min) {
-		return 0, sdk.Int{}, sdk.Int{}, sdk.Dec{}, time.Time{}, types.InsufficientLiquidityCreatedError{Actual: actualAmount0, Minimum: amount0Min, IsTokenZero: true}
+		return 0, sdk.Int{}, sdk.Int{}, sdk.Dec{}, time.Time{}, 0, 0, types.InsufficientLiquidityCreatedError{Actual: actualAmount0, Minimum: amount0Min, IsTokenZero: true}
 	}
 	if actualAmount1.LT(amount1Min) {
-		return 0, sdk.Int{}, sdk.Int{}, sdk.Dec{}, time.Time{}, types.InsufficientLiquidityCreatedError{Actual: actualAmount1, Minimum: amount1Min}
+		return 0, sdk.Int{}, sdk.Int{}, sdk.Dec{}, time.Time{}, 0, 0, types.InsufficientLiquidityCreatedError{Actual: actualAmount1, Minimum: amount1Min}
 	}
 
 	// Transfer the actual amounts of tokens 0 and 1 from the position owner to the pool.
 	err = k.sendCoinsBetweenPoolAndUser(ctx, pool.GetToken0(), pool.GetToken1(), actualAmount0, actualAmount1, owner, pool.GetAddress())
 	if err != nil {
-		return 0, sdk.Int{}, sdk.Int{}, sdk.Dec{}, time.Time{}, err
+		return 0, sdk.Int{}, sdk.Int{}, sdk.Dec{}, time.Time{}, 0, 0, err
 	}
 
 	emitLiquidityChangeEvent(ctx, types.TypeEvtCreatePosition, positionId, owner, poolId, lowerTick, upperTick, joinTime, liquidityDelta, actualAmount0, actualAmount1)
@@ -111,12 +117,12 @@ func (k Keeper) createPosition(ctx sdk.Context, poolId uint64, owner sdk.AccAddr
 	if !hasPositions {
 		// N.B. calling this listener propagates to x/twap for twap record creation.
 		// This is done after initial pool position only because only the first position
-		// initializes the pool's spot price. After initial position is created, only
+		// initializes the pool's spot price. After the initial position is created, only
 		// swaps update the spot price.
 		k.listeners.AfterInitialPoolPositionCreated(ctx, owner, poolId)
 	}
 
-	return positionId, actualAmount0, actualAmount1, liquidityDelta, joinTime, nil
+	return positionId, actualAmount0, actualAmount1, liquidityDelta, joinTime, lowerTick, upperTick, nil
 }
 
 // WithdrawPosition attempts to withdraw liquidityAmount from a position with the given pool id in the given tick range.
@@ -298,7 +304,7 @@ func (k Keeper) addToPosition(ctx sdk.Context, owner sdk.AccAddress, positionId
 		return 0, sdk.Int{}, sdk.Int{}, err
 	}
 	tokensProvided := sdk.NewCoins(sdk.NewCoin(pool.GetToken0(), amount0Desired), sdk.NewCoin(pool.GetToken1(), amount1Desired))
-	newPositionId, actualAmount0, actualAmount1, _, _, err := k.createPosition(ctx, position.PoolId, owner, tokensProvided, amount0Withdrawn, amount1Withdrawn, position.LowerTick, position.UpperTick)
+	newPositionId, actualAmount0, actualAmount1, _, _, _, _, err := k.createPosition(ctx, position.PoolId, owner, tokensProvided, amount0Withdrawn, amount1Withdrawn, position.LowerTick, position.UpperTick)
 	if err != nil {
 		return 0, sdk.Int{}, sdk.Int{}, err
 	}
diff --git a/x/concentrated-liquidity/math/precompute.go b/x/concentrated-liquidity/math/precompute.go
deleted file mode 100644
index 7996ba305..000000000
--- a/x/concentrated-liquidity/math/precompute.go
+++ /dev/null
@@ -1,44 +0,0 @@
-package math
-
-import (
-	sdk "github.com/cosmos/cosmos-sdk/types"
-
-	"github.com/osmosis-labs/osmosis/osmomath"
-)
-
-var (
-	sdkOneInt      = sdk.OneInt()
-	sdkOneDec      = sdk.NewDec(1)
-	sdkNineDec     = sdk.NewDec(9)
-	sdkTenDec      = sdk.NewDec(10)
-	powersOfTen    []sdk.Dec
-	negPowersOfTen []sdk.Dec
-
-	osmomathBigOneDec = osmomath.NewBigDec(1)
-	osmomathBigTenDec = osmomath.NewBigDec(10)
-	bigPowersOfTen    []osmomath.BigDec
-	bigNegPowersOfTen []osmomath.BigDec
-)
-
-// Set precision multipliers
-func init() {
-	negPowersOfTen = make([]sdk.Dec, sdk.Precision+1)
-	for i := 0; i <= sdk.Precision; i++ {
-		negPowersOfTen[i] = sdkOneDec.Quo(sdkTenDec.Power(uint64(i)))
-	}
-	// 10^77 < sdk.MaxInt < 10^78
-	powersOfTen = make([]sdk.Dec, 78)
-	for i := 0; i <= 77; i++ {
-		powersOfTen[i] = sdkTenDec.Power(uint64(i))
-	}
-
-	bigNegPowersOfTen = make([]osmomath.BigDec, osmomath.Precision+1)
-	for i := 0; i <= osmomath.Precision; i++ {
-		bigNegPowersOfTen[i] = osmomathBigOneDec.Quo(osmomathBigTenDec.PowerInteger(uint64(i)))
-	}
-	// 10^308 < osmomath.MaxInt < 10^309
-	bigPowersOfTen = make([]osmomath.BigDec, 309)
-	for i := 0; i <= 308; i++ {
-		bigPowersOfTen[i] = osmomathBigTenDec.PowerInteger(uint64(i))
-	}
-}
diff --git a/x/concentrated-liquidity/math/tick.go b/x/concentrated-liquidity/math/tick.go
index 5a1138a72..45972a17d 100644
--- a/x/concentrated-liquidity/math/tick.go
+++ b/x/concentrated-liquidity/math/tick.go
@@ -9,39 +9,44 @@ import (
 	"github.com/osmosis-labs/osmosis/v15/x/concentrated-liquidity/types"
 )
 
+var (
+	sdkNineDec = sdk.NewDec(9)
+	sdkTenDec  = sdk.NewDec(10)
+)
+
 // 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) (sdk.Dec, sdk.Dec, sdk.Dec, sdk.Dec, error) {
 	if lowerTick >= upperTick {
-		return sdk.Dec{}, sdk.Dec{}, types.InvalidLowerUpperTickError{LowerTick: lowerTick, UpperTick: upperTick}
+		return sdk.Dec{}, sdk.Dec{}, sdk.Dec{}, sdk.Dec{}, types.InvalidLowerUpperTickError{LowerTick: lowerTick, UpperTick: upperTick}
 	}
-	sqrtPriceUpperTick, err := TickToSqrtPrice(sdk.NewInt(upperTick))
+	priceUpperTick, sqrtPriceUpperTick, err := TickToSqrtPrice(sdk.NewInt(upperTick))
 	if err != nil {
-		return sdk.Dec{}, sdk.Dec{}, err
+		return sdk.Dec{}, sdk.Dec{}, sdk.Dec{}, sdk.Dec{}, err
 	}
-	sqrtPriceLowerTick, err := TickToSqrtPrice(sdk.NewInt(lowerTick))
+	priceLowerTick, sqrtPriceLowerTick, err := TickToSqrtPrice(sdk.NewInt(lowerTick))
 	if err != nil {
-		return sdk.Dec{}, sdk.Dec{}, err
+		return sdk.Dec{}, sdk.Dec{}, sdk.Dec{}, sdk.Dec{}, err
 	}
-	return sqrtPriceLowerTick, sqrtPriceUpperTick, nil
+	return priceLowerTick, priceUpperTick, sqrtPriceLowerTick, sqrtPriceUpperTick, nil
 }
 
 // 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 sdk.Int) (sdk.Dec, error) {
+func TickToSqrtPrice(tickIndex sdk.Int) (sdk.Dec, sdk.Dec, error) {
 	price, err := TickToPrice(tickIndex)
 	if err != nil {
-		return sdk.Dec{}, err
+		return sdk.Dec{}, sdk.Dec{}, err
 	}
 
 	// Determine the sqrtPrice from the price
 	sqrtPrice, err := price.ApproxSqrt()
 	if err != nil {
-		return sdk.Dec{}, err
+		return sdk.Dec{}, sdk.Dec{}, err
 	}
-	return sqrtPrice, nil
+	return price, sqrtPrice, nil
 }
 
 // TickToPrice returns the price given a tickIndex
@@ -72,7 +77,7 @@ func TickToPrice(tickIndex sdk.Int) (price sdk.Dec, err error) {
 	if tickIndex.IsNegative() {
 		// We must decrement the exponentAtCurrentTick when entering the negative tick range in order to constantly step up in precision when going further down in ticks
 		// Otherwise, from tick 0 to tick -(geometricExponentIncrementDistanceInTicks), we would use the same exponent as the exponentAtPriceOne
-		exponentAtCurrentTick = exponentAtCurrentTick.Sub(sdkOneInt)
+		exponentAtCurrentTick = exponentAtCurrentTick.Sub(sdk.OneInt())
 	}
 
 	// Knowing what our exponentAtCurrentTick is, we can then figure out what power of 10 this exponent corresponds to
@@ -141,16 +146,16 @@ func PriceToTickRoundDown(price sdk.Dec, tickSpacing uint64) (sdk.Int, error) {
 // This is because the sdk.Dec.Power function does not support negative exponents
 func PowTenInternal(exponent sdk.Int) sdk.Dec {
 	if exponent.GTE(sdk.ZeroInt()) {
-		return powersOfTen[exponent.Int64()]
+		return sdkTenDec.Power(exponent.Uint64())
 	}
-	return negPowersOfTen[-exponent.Int64()]
+	return sdk.OneDec().Quo(sdkTenDec.Power(exponent.Abs().Uint64()))
 }
 
 func powTenBigDec(exponent sdk.Int) osmomath.BigDec {
 	if exponent.GTE(sdk.ZeroInt()) {
-		return bigPowersOfTen[exponent.Int64()]
+		return osmomath.NewBigDec(10).PowerInteger(exponent.Uint64())
 	}
-	return bigNegPowersOfTen[-exponent.Int64()]
+	return osmomath.OneDec().Quo(osmomath.NewBigDec(10).PowerInteger(exponent.Abs().Uint64()))
 }
 
 // CalculatePriceToTick takes in a price and returns the corresponding tick index.
@@ -175,23 +180,23 @@ func CalculatePriceToTick(price sdk.Dec) (tickIndex sdk.Int) {
 	// as well as how many ticks that corresponds to
 	// In the opposite direction (price < 1), we do the same thing (just decrement the geometric exponent instead of incrementing).
 	// The only difference is we must reduce the increment distance by a factor of 10.
-	if price.GT(sdkOneDec) {
+	if price.GT(sdk.OneDec()) {
 		for currentPrice.LT(price) {
 			currentAdditiveIncrementInTicks = powTenBigDec(exponentAtCurrentTick)
 			maxPriceForCurrentAdditiveIncrementInTicks := osmomath.BigDecFromSDKDec(geometricExponentIncrementDistanceInTicks).Mul(currentAdditiveIncrementInTicks)
-			currentPrice.AddMut(maxPriceForCurrentAdditiveIncrementInTicks.SDKDec())
-			exponentAtCurrentTick = exponentAtCurrentTick.Add(sdkOneInt)
+			currentPrice = currentPrice.Add(maxPriceForCurrentAdditiveIncrementInTicks.SDKDec())
+			exponentAtCurrentTick = exponentAtCurrentTick.Add(sdk.OneInt())
 			ticksPassed = ticksPassed.Add(geometricExponentIncrementDistanceInTicks.TruncateInt())
 		}
 	} else {
 		// We must decrement the exponentAtCurrentTick by one when traversing negative ticks in order to constantly step up in precision when going further down in ticks
 		// Otherwise, from tick 0 to tick -(geometricExponentIncrementDistanceInTicks), we would use the same exponent as the exponentAtPriceOne
-		exponentAtCurrentTick := exponentAtPriceOne.Sub(sdkOneInt)
+		exponentAtCurrentTick := exponentAtPriceOne.Sub(sdk.OneInt())
 		for currentPrice.GT(price) {
 			currentAdditiveIncrementInTicks = powTenBigDec(exponentAtCurrentTick)
 			maxPriceForCurrentAdditiveIncrementInTicks := osmomath.BigDecFromSDKDec(geometricExponentIncrementDistanceInTicks).Mul(currentAdditiveIncrementInTicks)
-			currentPrice.SubMut(maxPriceForCurrentAdditiveIncrementInTicks.SDKDec())
-			exponentAtCurrentTick = exponentAtCurrentTick.Sub(sdkOneInt)
+			currentPrice = currentPrice.Sub(maxPriceForCurrentAdditiveIncrementInTicks.SDKDec())
+			exponentAtCurrentTick = exponentAtCurrentTick.Sub(sdk.OneInt())
 			ticksPassed = ticksPassed.Sub(geometricExponentIncrementDistanceInTicks.TruncateInt())
 		}
 	}
diff --git a/x/concentrated-liquidity/model/pool.go b/x/concentrated-liquidity/model/pool.go
index 123c15378..4e3d08572 100644
--- a/x/concentrated-liquidity/model/pool.go
+++ b/x/concentrated-liquidity/model/pool.go
@@ -221,7 +221,7 @@ func (p Pool) CalcActualAmounts(ctx sdk.Context, lowerTick, upperTick int64, liq
 	}
 
 	// Transform the provided ticks into their corresponding sqrtPrices.
-	sqrtPriceLowerTick, sqrtPriceUpperTick, err := math.TicksToSqrtPrice(lowerTick, upperTick)
+	_, _, sqrtPriceLowerTick, sqrtPriceUpperTick, err := math.TicksToSqrtPrice(lowerTick, upperTick)
 	if err != nil {
 		return sdk.Dec{}, sdk.Dec{}, err
 	}
diff --git a/x/concentrated-liquidity/msg_server.go b/x/concentrated-liquidity/msg_server.go
index 0ad3a7bcb..fba3525c9 100644
--- a/x/concentrated-liquidity/msg_server.go
+++ b/x/concentrated-liquidity/msg_server.go
@@ -53,7 +53,7 @@ func (server msgServer) CreatePosition(goCtx context.Context, msg *types.MsgCrea
 		return nil, err
 	}
 
-	positionId, actualAmount0, actualAmount1, liquidityCreated, joinTime, err := server.keeper.createPosition(ctx, msg.PoolId, sender, msg.TokensProvided, msg.TokenMinAmount0, msg.TokenMinAmount1, msg.LowerTick, msg.UpperTick)
+	positionId, actualAmount0, actualAmount1, liquidityCreated, joinTime, lowerTick, upperTick, err := server.keeper.createPosition(ctx, msg.PoolId, sender, msg.TokensProvided, msg.TokenMinAmount0, msg.TokenMinAmount1, msg.LowerTick, msg.UpperTick)
 	if err != nil {
 		return nil, err
 	}
@@ -68,7 +68,7 @@ func (server msgServer) CreatePosition(goCtx context.Context, msg *types.MsgCrea
 
 	// Note: create position event is emitted in keeper.createPosition(...)
 
-	return &types.MsgCreatePositionResponse{PositionId: positionId, Amount0: actualAmount0, Amount1: actualAmount1, JoinTime: joinTime, LiquidityCreated: liquidityCreated}, nil
+	return &types.MsgCreatePositionResponse{PositionId: positionId, Amount0: actualAmount0, Amount1: actualAmount1, JoinTime: joinTime, LiquidityCreated: liquidityCreated, LowerTick: lowerTick, UpperTick: upperTick}, nil
 }
 
 func (server msgServer) AddToPosition(goCtx context.Context, msg *types.MsgAddToPosition) (*types.MsgAddToPositionResponse, error) {
diff --git a/x/concentrated-liquidity/position.go b/x/concentrated-liquidity/position.go
index 81b471c44..8639a0e5b 100644
--- a/x/concentrated-liquidity/position.go
+++ b/x/concentrated-liquidity/position.go
@@ -309,7 +309,7 @@ func (k Keeper) CreateFullRangePosition(ctx sdk.Context, clPoolId uint64, owner
 	}
 
 	// Create a full range (min to max tick) concentrated liquidity position.
-	positionId, amount0, amount1, liquidity, joinTime, err = k.createPosition(ctx, concentratedPool.GetId(), owner, coins, sdk.ZeroInt(), sdk.ZeroInt(), types.MinTick, types.MaxTick)
+	positionId, amount0, amount1, liquidity, joinTime, _, _, err = k.createPosition(ctx, concentratedPool.GetId(), owner, coins, sdk.ZeroInt(), sdk.ZeroInt(), types.MinTick, types.MaxTick)
 	if err != nil {
 		return 0, sdk.Int{}, sdk.Int{}, sdk.Dec{}, time.Time{}, err
 	}
diff --git a/x/concentrated-liquidity/swaps.go b/x/concentrated-liquidity/swaps.go
index 17250d66c..f0e5dcf18 100644
--- a/x/concentrated-liquidity/swaps.go
+++ b/x/concentrated-liquidity/swaps.go
@@ -66,7 +66,7 @@ func (ss *SwapState) updateFeeGrowthGlobal(feeChargeTotal sdk.Dec) {
 		// We round down here since we want to avoid overdistributing (the "fee charge" refers to
 		// the total fees that will be accrued to the fee accumulator)
 		feesAccruedPerUnitOfLiquidity := feeChargeTotal.QuoTruncate(ss.liquidity)
-		ss.feeGrowthGlobal.AddMut(feesAccruedPerUnitOfLiquidity)
+		ss.feeGrowthGlobal = ss.feeGrowthGlobal.Add(feesAccruedPerUnitOfLiquidity)
 		return
 	}
 }
@@ -335,8 +335,8 @@ func (k Keeper) calcOutAmtGivenIn(ctx sdk.Context,
 			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).
-		nextTickSqrtPrice, err := math.TickToSqrtPrice(nextTick)
+		// Utilizing the next initialized tick, we find the corresponding nextPrice (the target price)
+		_, nextTickSqrtPrice, err := math.TickToSqrtPrice(nextTick)
 		if err != nil {
 			return writeCtx, sdk.Coin{}, sdk.Coin{}, sdk.Int{}, sdk.Dec{}, sdk.Dec{}, fmt.Errorf("could not convert next tick (%v) to nextSqrtPrice", nextTick)
 		}
@@ -502,7 +502,7 @@ func (k Keeper) calcInAmtGivenOut(
 		}
 
 		// utilizing the next initialized tick, we find the corresponding nextPrice (the target price)
-		sqrtPriceNextTick, err := math.TickToSqrtPrice(nextTick)
+		_, sqrtPriceNextTick, err := math.TickToSqrtPrice(nextTick)
 		if err != nil {
 			return writeCtx, sdk.Coin{}, sdk.Coin{}, sdk.Int{}, sdk.Dec{}, sdk.Dec{}, fmt.Errorf("could not convert next tick (%v) to nextSqrtPrice", nextTick)
 		}
diff --git a/x/concentrated-liquidity/tick.go b/x/concentrated-liquidity/tick.go
index 09a62ec34..c84ece6d0 100644
--- a/x/concentrated-liquidity/tick.go
+++ b/x/concentrated-liquidity/tick.go
@@ -191,6 +191,37 @@ func validateTickRangeIsValid(tickSpacing uint64, lowerTick int64, upperTick int
 	return nil
 }
 
+// roundTickToCanonicalPriceTick takes a tick and determines if multiple ticks can represent the same price as the provided tick. If so, it
+// rounds that tick up to the largest tick that can represent the same price that the original tick corresponded to. If one of
+// the two ticks happen to be rounded, we re-validate the tick range to ensure that the tick range is still valid.
+//
+// i.e. the provided tick is -161795100. With our precision, this tick correlates to a sqrtPrice of 0.000000001414213563
+// 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, priceTickLower, priceTickUpper sdk.Dec, tickSpacing uint64) (int64, int64, error) {
+	newLowerTick, err := math.PriceToTickRoundDown(priceTickLower, tickSpacing)
+	if err != nil {
+		return 0, 0, err
+	}
+	newUpperTick, err := math.PriceToTickRoundDown(priceTickUpper, tickSpacing)
+	if err != nil {
+		return 0, 0, err
+	}
+
+	newLowerTickInt64 := newLowerTick.Int64()
+	newUpperTickInt64 := newUpperTick.Int64()
+
+	// If the lower or upper tick has changed, we need to re-validate the tick range.
+	if lowerTick != newLowerTickInt64 || upperTick != newUpperTickInt64 {
+		err := validateTickRangeIsValid(tickSpacing, newLowerTickInt64, newUpperTickInt64)
+		if err != nil {
+			return 0, 0, err
+		}
+	}
+	return newLowerTickInt64, newUpperTickInt64, nil
+}
+
 // GetTickLiquidityForFullRange returns an array of liquidity depth for all ticks existing from min tick ~ max tick.
 func (k Keeper) GetTickLiquidityForFullRange(ctx sdk.Context, poolId uint64) ([]queryproto.LiquidityDepthWithRange, error) {
 	pool, err := k.getPoolById(ctx, poolId)
@@ -332,7 +363,7 @@ func (k Keeper) GetTickLiquidityNetInDirection(ctx sdk.Context, poolId uint64, t
 	swapStrategy := swapstrategy.New(zeroForOne, sdk.ZeroDec(), k.storeKey, sdk.ZeroDec(), p.GetTickSpacing())
 
 	currentTick := p.GetCurrentTick()
-	currentTickSqrtPrice, err := math.TickToSqrtPrice(currentTick)
+	_, currentTickSqrtPrice, err := math.TickToSqrtPrice(currentTick)
 	if err != nil {
 		return []queryproto.TickLiquidityNet{}, err
 	}
@@ -342,7 +373,7 @@ func (k Keeper) GetTickLiquidityNetInDirection(ctx sdk.Context, poolId uint64, t
 	// function to validate that start tick and bound tick are
 	// between current tick and the min/max tick depending on the swap direction.
 	validateTickIsInValidRange := func(validateTick sdk.Int) error {
-		validateSqrtPrice, err := math.TickToSqrtPrice(validateTick)
+		_, validateSqrtPrice, err := math.TickToSqrtPrice(validateTick)
 		if err != nil {
 			return err
 		}
diff --git a/x/concentrated-liquidity/types/tx.pb.go b/x/concentrated-liquidity/types/tx.pb.go
index 2929b8389..1e8cd211e 100644
--- a/x/concentrated-liquidity/types/tx.pb.go
+++ b/x/concentrated-liquidity/types/tx.pb.go
@@ -123,6 +123,12 @@ type MsgCreatePositionResponse struct {
 	Amount1          github_com_cosmos_cosmos_sdk_types.Int `protobuf:"bytes,3,opt,name=amount1,proto3,customtype=github.com/cosmos/cosmos-sdk/types.Int" json:"amount1" yaml:"amount1"`
 	JoinTime         time.Time                              `protobuf:"bytes,4,opt,name=join_time,json=joinTime,proto3,stdtime" json:"join_time" yaml:"join_time"`
 	LiquidityCreated github_com_cosmos_cosmos_sdk_types.Dec `protobuf:"bytes,5,opt,name=liquidity_created,json=liquidityCreated,proto3,customtype=github.com/cosmos/cosmos-sdk/types.Dec" json:"liquidity_created" yaml:"liquidity_created"`
+	// the lower and upper tick are in the response because there are
+	// instances in which multiple ticks represent the same price, so
+	// we may move their provided tick to the canonical tick that represents
+	// the same price.
+	LowerTick int64 `protobuf:"varint,6,opt,name=lower_tick,json=lowerTick,proto3" json:"lower_tick,omitempty" yaml:"lower_tick"`
+	UpperTick int64 `protobuf:"varint,7,opt,name=upper_tick,json=upperTick,proto3" json:"upper_tick,omitempty" yaml:"upper_tick"`
 }
 
 func (m *MsgCreatePositionResponse) Reset()         { *m = MsgCreatePositionResponse{} }
@@ -172,6 +178,20 @@ func (m *MsgCreatePositionResponse) GetJoinTime() time.Time {
 	return time.Time{}
 }
 
+func (m *MsgCreatePositionResponse) GetLowerTick() int64 {
+	if m != nil {
+		return m.LowerTick
+	}
+	return 0
+}
+
+func (m *MsgCreatePositionResponse) GetUpperTick() int64 {
+	if m != nil {
+		return m.UpperTick
+	}
+	return 0
+}
+
 // ===================== MsgAddToPosition
 type MsgAddToPosition struct {
 	PositionId    uint64     `protobuf:"varint,1,opt,name=position_id,json=positionId,proto3" json:"position_id,omitempty" yaml:"position_id"`
@@ -840,89 +860,90 @@ func init() {
 }
 
 var fileDescriptor_1f1fff802923d7db = []byte{
-	// 1305 bytes of a gzipped FileDescriptorProto
-	0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xe4, 0x58, 0x4f, 0x6f, 0xdc, 0x44,
-	0x14, 0x8f, 0x77, 0xd3, 0xb4, 0x99, 0x74, 0xf3, 0xc7, 0x49, 0xdb, 0xad, 0x5b, 0xd6, 0xd1, 0x20,
-	0xe8, 0x22, 0xa8, 0x5d, 0xb7, 0x54, 0x40, 0x11, 0xa2, 0x75, 0xa2, 0x4a, 0x8b, 0x14, 0xa9, 0xb2,
-	0x5a, 0x81, 0x2a, 0x24, 0xcb, 0xbb, 0x9e, 0x6c, 0x86, 0xac, 0x3d, 0x5b, 0xcf, 0x6c, 0xd2, 0x3d,
-	0x70, 0x2a, 0x17, 0x04, 0x52, 0x2b, 0x24, 0x24, 0xbe, 0x01, 0x12, 0x9f, 0x80, 0x0b, 0xf7, 0x1e,
-	0x7b, 0x41, 0x42, 0x08, 0x6d, 0x51, 0x73, 0xe3, 0x82, 0xd8, 0x4f, 0x80, 0xec, 0xb1, 0xc7, 0x1b,
-	0x3b, 0xa1, 0xf1, 0xa6, 0xc9, 0x85, 0x53, 0x32, 0x6f, 0xde, 0xef, 0xf7, 0x9b, 0x79, 0xef, 0xcd,
-	0xcc, 0xf3, 0x82, 0x4b, 0x84, 0x7a, 0x84, 0x62, 0xaa, 0xb7, 0x88, 0xdf, 0x42, 0x3e, 0x0b, 0x1c,
-	0x86, 0xdc, 0xcb, 0x1d, 0xfc, 0xa0, 0x87, 0x5d, 0xcc, 0xfa, 0x3a, 0x7b, 0xa8, 0x75, 0x03, 0xc2,
-	0x88, 0xfc, 0x46, 0xec, 0xa8, 0x8d, 0x3a, 0x0a, 0x3f, 0x6d, 0xcb, 0x68, 0x22, 0xe6, 0x18, 0xca,
-	0x52, 0x9b, 0xb4, 0x49, 0x84, 0xd0, 0xc3, 0xff, 0x38, 0x58, 0x51, 0xdb, 0x84, 0xb4, 0x3b, 0x48,
-	0x8f, 0x46, 0xcd, 0xde, 0xba, 0xce, 0xb0, 0x87, 0x28, 0x73, 0xbc, 0x6e, 0xec, 0x50, 0xcb, 0x3a,
-	0xb8, 0xbd, 0xc0, 0x61, 0x98, 0xf8, 0xc9, 0x7c, 0x2b, 0x92, 0xd7, 0x9b, 0x0e, 0x45, 0x7a, 0xac,
-	0xa5, 0xb7, 0x08, 0x8e, 0xe7, 0xe1, 0x2f, 0x93, 0x60, 0x61, 0x8d, 0xb6, 0x57, 0x02, 0xe4, 0x30,
-	0x74, 0x87, 0x50, 0x1c, 0x62, 0xe5, 0xb7, 0xc1, 0xc9, 0x2e, 0x21, 0x1d, 0x1b, 0xbb, 0x55, 0x69,
-	0x59, 0xaa, 0x4f, 0x9a, 0xf2, 0x70, 0xa0, 0xce, 0xf6, 0x1d, 0xaf, 0x73, 0x03, 0xc6, 0x13, 0xd0,
-	0x9a, 0x0a, 0xff, 0x6b, 0xb8, 0xf2, 0x5b, 0x60, 0x8a, 0x22, 0xdf, 0x45, 0x41, 0xb5, 0xb4, 0x2c,
-	0xd5, 0xa7, 0xcd, 0x85, 0xe1, 0x40, 0xad, 0x70, 0x5f, 0x6e, 0x87, 0x56, 0xec, 0x20, 0xbf, 0x0b,
-	0x40, 0x87, 0x6c, 0xa3, 0xc0, 0x66, 0xb8, 0xb5, 0x59, 0x2d, 0x2f, 0x4b, 0xf5, 0xb2, 0x79, 0x66,
-	0x38, 0x50, 0x17, 0xb8, 0x7b, 0x3a, 0x07, 0xad, 0xe9, 0x68, 0x70, 0x17, 0xb7, 0x36, 0x43, 0x54,
-	0xaf, 0xdb, 0x4d, 0x50, 0x93, 0x59, 0x54, 0x3a, 0x07, 0xad, 0xe9, 0x68, 0x10, 0xa1, 0x18, 0x98,
-	0x63, 0x64, 0x13, 0xf9, 0xd4, 0xee, 0x06, 0x64, 0x0b, 0xbb, 0xc8, 0xad, 0x9e, 0x58, 0x2e, 0xd7,
-	0x67, 0xae, 0x9e, 0xd7, 0x78, 0x4c, 0xb4, 0x30, 0x26, 0x49, 0xfc, 0xb5, 0x15, 0x82, 0x7d, 0xf3,
-	0xca, 0xd3, 0x81, 0x3a, 0xf1, 0xd3, 0x73, 0xb5, 0xde, 0xc6, 0x6c, 0xa3, 0xd7, 0xd4, 0x5a, 0xc4,
-	0xd3, 0xe3, 0x00, 0xf2, 0x3f, 0x97, 0xa9, 0xbb, 0xa9, 0xb3, 0x7e, 0x17, 0xd1, 0x08, 0x40, 0xad,
-	0x59, 0xae, 0x71, 0x27, 0x96, 0x90, 0xb7, 0xc0, 0x42, 0x64, 0xb1, 0x3d, 0xec, 0xdb, 0x8e, 0x47,
-	0x7a, 0x3e, 0xbb, 0x52, 0x9d, 0x8a, 0xe2, 0xf2, 0x49, 0x48, 0xfe, 0xfb, 0x40, 0x7d, 0xf3, 0x00,
-	0xe4, 0x0d, 0x9f, 0x0d, 0x07, 0x6a, 0x95, 0x6f, 0x30, 0x47, 0x08, 0x2d, 0xbe, 0xb5, 0x35, 0xec,
-	0xdf, 0xe2, 0x96, 0xbd, 0x74, 0x8d, 0xea, 0xc9, 0x57, 0xab, 0x6b, 0xe4, 0x74, 0x0d, 0xf8, 0x47,
-	0x19, 0x9c, 0xcf, 0xd5, 0x8f, 0x85, 0x68, 0x97, 0xf8, 0x14, 0xc9, 0xef, 0x81, 0x99, 0x6e, 0x6c,
-	0x4b, 0x6b, 0xe9, 0xec, 0x70, 0xa0, 0xca, 0x49, 0x2d, 0x89, 0x49, 0x68, 0x81, 0x64, 0xd4, 0x70,
-	0xe5, 0xfb, 0xe0, 0x64, 0x12, 0x3c, 0x5e, 0x54, 0x37, 0x0b, 0x6f, 0x22, 0x2e, 0x57, 0x11, 0xb2,
-	0x84, 0x30, 0xe5, 0x36, 0xa2, 0x0a, 0x3c, 0x34, 0xb7, 0x21, 0xb8, 0x0d, 0xf9, 0x1e, 0x98, 0xfe,
-	0x82, 0x60, 0xdf, 0x0e, 0x8f, 0x69, 0x54, 0xa9, 0x33, 0x57, 0x15, 0x8d, 0x1f, 0x51, 0x2d, 0x39,
-	0xa2, 0xda, 0xdd, 0xe4, 0x0c, 0x9b, 0x17, 0x43, 0xe5, 0xe1, 0x40, 0x9d, 0xe7, 0x7c, 0x02, 0x0a,
-	0x9f, 0x3c, 0x57, 0x25, 0xeb, 0x54, 0x38, 0x0e, 0x9d, 0xe5, 0x6d, 0xb0, 0x20, 0x6e, 0x0c, 0xbb,
-	0x15, 0xc5, 0x3a, 0xac, 0xe6, 0xa2, 0xd9, 0x5d, 0x45, 0xad, 0x34, 0xbb, 0x39, 0x42, 0x68, 0xcd,
-	0x0b, 0xdb, 0x4a, 0x6c, 0xfa, 0xb9, 0x04, 0xe6, 0xd7, 0x68, 0xfb, 0x96, 0xeb, 0xde, 0x25, 0xe2,
-	0x76, 0x18, 0x3b, 0xab, 0x05, 0x6e, 0x0a, 0x1b, 0xf0, 0x93, 0x65, 0xbb, 0x88, 0xe2, 0x00, 0xb9,
-	0x57, 0xa2, 0x5c, 0xfd, 0xe7, 0xe1, 0x7d, 0x2d, 0x0e, 0xe6, 0x99, 0xd1, 0xea, 0x4d, 0xe0, 0xd0,
-	0xaa, 0x44, 0x86, 0xd5, 0x78, 0x9c, 0x13, 0x30, 0xe2, 0x74, 0x8d, 0x29, 0x60, 0x64, 0x04, 0x0c,
-	0xf8, 0x4d, 0x09, 0x54, 0xb3, 0xa1, 0xfb, 0xdf, 0x1e, 0x0c, 0xf8, 0xb7, 0x04, 0x16, 0xd7, 0x68,
-	0xfb, 0x53, 0xcc, 0x36, 0xdc, 0xc0, 0xd9, 0x3e, 0xd6, 0x5a, 0x62, 0x20, 0x2d, 0xec, 0xf8, 0x2a,
-	0x8b, 0x37, 0xd8, 0x28, 0x7c, 0x78, 0xce, 0x65, 0x0f, 0x0f, 0xe7, 0x83, 0xd6, 0x9c, 0x30, 0xf1,
-	0xab, 0x11, 0xfe, 0x2a, 0x81, 0x0b, 0x7b, 0xec, 0x58, 0x94, 0xc0, 0x48, 0x26, 0xa5, 0x23, 0xcc,
-	0x64, 0xe9, 0x55, 0x67, 0x72, 0x1b, 0xcc, 0x86, 0x17, 0x3e, 0xe9, 0x74, 0x50, 0x8b, 0xdd, 0x46,
-	0x88, 0xca, 0x37, 0xc0, 0xe9, 0x91, 0x34, 0xd1, 0xaa, 0xb4, 0x5c, 0xae, 0x4f, 0x9a, 0xe7, 0x86,
-	0x03, 0x75, 0x31, 0x97, 0x44, 0x0a, 0xad, 0x99, 0x34, 0x8b, 0xb4, 0x40, 0x1a, 0x61, 0x1f, 0x9c,
-	0xdd, 0x2d, 0x2c, 0x42, 0x69, 0x83, 0xd9, 0x16, 0x37, 0x23, 0xd7, 0x5e, 0x47, 0x88, 0x2f, 0xa1,
-	0xc8, 0x59, 0xde, 0x0d, 0x87, 0x56, 0x45, 0x18, 0x42, 0x21, 0xf8, 0x25, 0x58, 0x4a, 0xa5, 0x1b,
-	0x51, 0x1b, 0x87, 0xb7, 0x8e, 0x6f, 0xe7, 0x5f, 0x95, 0xc0, 0xc5, 0xbd, 0xf4, 0x45, 0x00, 0x1e,
-	0x80, 0xa5, 0x74, 0x07, 0x58, 0xcc, 0xbf, 0x3c, 0x0c, 0xaf, 0xc7, 0x61, 0xb8, 0x90, 0x0d, 0x43,
-	0x4a, 0x02, 0xad, 0x45, 0x61, 0x1e, 0xd9, 0xfa, 0x03, 0xb0, 0xb4, 0x4e, 0x82, 0x75, 0x84, 0x33,
-	0x92, 0xa5, 0x82, 0x92, 0x7b, 0x91, 0x40, 0x6b, 0x51, 0x98, 0x53, 0x49, 0xf8, 0x68, 0x12, 0xc8,
-	0xa2, 0xd7, 0x10, 0xf6, 0x23, 0x6b, 0x56, 0x6d, 0x30, 0x2b, 0x96, 0x64, 0x87, 0x2d, 0x73, 0xe1,
-	0x27, 0x68, 0x37, 0x1c, 0x5a, 0x15, 0x61, 0x08, 0xbd, 0xe5, 0x4d, 0x50, 0x41, 0x1e, 0xa6, 0x34,
-	0xac, 0x8f, 0xf0, 0xab, 0x20, 0x7a, 0x81, 0xa6, 0xcd, 0xdb, 0x85, 0x2f, 0xa5, 0x25, 0x2e, 0xb7,
-	0x8b, 0x0c, 0x5a, 0xa7, 0x93, 0xb1, 0xe5, 0x30, 0x24, 0x7f, 0x06, 0x00, 0x65, 0x4e, 0xc0, 0x78,
-	0x6b, 0x72, 0xe2, 0xa5, 0xad, 0x49, 0xb2, 0x95, 0xb8, 0xc9, 0x4e, 0xb1, 0xbc, 0x37, 0x99, 0x8e,
-	0x0c, 0x51, 0x73, 0xe2, 0x01, 0x10, 0xf6, 0x88, 0xbd, 0x6e, 0xc4, 0x3c, 0x15, 0xc7, 0x28, 0xcb,
-	0xbc, 0x1a, 0x7f, 0x97, 0x98, 0xd7, 0x42, 0xe2, 0xbf, 0x06, 0xaa, 0x9c, 0x7c, 0xa9, 0xbc, 0x43,
-	0x3c, 0xcc, 0x90, 0xd7, 0x65, 0xfd, 0x54, 0x2e, 0x25, 0x84, 0x3f, 0x44, 0x72, 0x1e, 0xf6, 0xef,
-	0xf1, 0xf1, 0x3f, 0x65, 0xa0, 0xe4, 0xab, 0x40, 0x1c, 0x85, 0x4b, 0x60, 0x2e, 0x0d, 0xbb, 0x8b,
-	0x7c, 0xe2, 0xf1, 0xeb, 0xd5, 0x4a, 0x93, 0xb9, 0x1a, 0x5a, 0xc3, 0x57, 0x21, 0x75, 0x8c, 0x5f,
-	0x85, 0xd2, 0xe1, 0x5e, 0x85, 0x2c, 0x1f, 0xb4, 0xd2, 0xb5, 0xf0, 0x57, 0x21, 0x9f, 0xf3, 0xf2,
-	0xb1, 0xe5, 0x7c, 0xf2, 0xc8, 0x72, 0x7e, 0xe2, 0xa8, 0x73, 0xfe, 0x48, 0x8a, 0x72, 0x7e, 0xbb,
-	0xe7, 0xb7, 0xf1, 0x7a, 0x7f, 0x65, 0xc3, 0x09, 0xda, 0xc8, 0x4d, 0x5e, 0xd4, 0x63, 0xbb, 0x86,
-	0x37, 0x00, 0xdc, 0x7f, 0x11, 0xa2, 0x00, 0x4d, 0x30, 0xe7, 0xa3, 0x6d, 0x3b, 0xdf, 0xd5, 0x28,
-	0xc3, 0x81, 0x7a, 0x96, 0x33, 0x67, 0x1c, 0xa0, 0x55, 0xf1, 0x91, 0xe8, 0x10, 0x1a, 0xee, 0xd5,
-	0xc7, 0xa7, 0x40, 0x79, 0x8d, 0xb6, 0xe5, 0x6f, 0x25, 0x30, 0x9b, 0xf9, 0x34, 0x7f, 0x5f, 0x3b,
-	0xd0, 0xef, 0x09, 0x5a, 0xee, 0xa3, 0x4c, 0xb9, 0x39, 0x2e, 0x52, 0x6c, 0xed, 0x3b, 0x09, 0xcc,
-	0xe7, 0x3a, 0xb8, 0x1b, 0x07, 0xa7, 0xcd, 0x62, 0x15, 0x73, 0x7c, 0xac, 0x58, 0xd4, 0xd7, 0x12,
-	0xa8, 0x64, 0xbe, 0x4f, 0x0e, 0xce, 0xba, 0x0b, 0xa8, 0x7c, 0x3c, 0x26, 0x50, 0xac, 0xe5, 0x91,
-	0x04, 0x66, 0x46, 0x3b, 0xa3, 0xeb, 0x05, 0x42, 0x9e, 0xc2, 0x94, 0x8f, 0xc6, 0x82, 0x89, 0x55,
-	0x7c, 0x2f, 0x81, 0x85, 0x7c, 0xaf, 0xf2, 0x61, 0x61, 0xd2, 0x14, 0xac, 0xac, 0x1c, 0x02, 0x2c,
-	0xd6, 0xf5, 0x58, 0x02, 0x73, 0xd9, 0xc7, 0xfb, 0x83, 0xa2, 0x45, 0x29, 0xa0, 0xca, 0xad, 0xb1,
-	0xa1, 0x62, 0x45, 0x3f, 0x4a, 0xe0, 0xdc, 0x7e, 0x97, 0x4a, 0x01, 0xfa, 0x7d, 0x28, 0x94, 0xc6,
-	0xa1, 0x29, 0x92, 0x95, 0x9a, 0x9f, 0x3f, 0x7d, 0x51, 0x93, 0x9e, 0xbd, 0xa8, 0x49, 0x7f, 0xbe,
-	0xa8, 0x49, 0x4f, 0x76, 0x6a, 0x13, 0xcf, 0x76, 0x6a, 0x13, 0xbf, 0xed, 0xd4, 0x26, 0xee, 0x9b,
-	0x23, 0x4f, 0x46, 0x2c, 0x77, 0xb9, 0xe3, 0x34, 0x69, 0x32, 0xd0, 0xb7, 0x8c, 0xeb, 0xfa, 0xc3,
-	0x7d, 0x7f, 0xa6, 0x0c, 0x9f, 0x94, 0xe6, 0x54, 0x74, 0x65, 0x5f, 0xfb, 0x37, 0x00, 0x00, 0xff,
-	0xff, 0x60, 0x55, 0xb4, 0xb7, 0xd5, 0x14, 0x00, 0x00,
+	// 1318 bytes of a gzipped FileDescriptorProto
+	0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xe4, 0x58, 0xcf, 0x6f, 0xdc, 0xc4,
+	0x17, 0x8f, 0x77, 0xb7, 0x49, 0x33, 0xe9, 0xe6, 0x87, 0x93, 0xb6, 0x5b, 0xb7, 0xdf, 0x75, 0x34,
+	0x5f, 0x41, 0x83, 0xa0, 0x76, 0xdd, 0x52, 0x01, 0x45, 0x88, 0xd6, 0x89, 0x2a, 0x2d, 0x52, 0xa4,
+	0xca, 0x6a, 0x05, 0xaa, 0x90, 0x2c, 0xef, 0x7a, 0xb2, 0x19, 0xb2, 0xf6, 0x6c, 0x3d, 0xb3, 0x49,
+	0xf7, 0xc0, 0xa9, 0x5c, 0x10, 0x48, 0xad, 0x90, 0x90, 0xf8, 0x0f, 0x90, 0xf8, 0x0b, 0xb8, 0x70,
+	0xef, 0xb1, 0x17, 0x24, 0xc4, 0x61, 0x8b, 0x9a, 0x1b, 0x17, 0xc4, 0xfe, 0x05, 0xc8, 0x1e, 0x7b,
+	0xbc, 0xb1, 0x13, 0x1a, 0x6f, 0x9a, 0x5c, 0x38, 0x25, 0xf3, 0xe6, 0x7d, 0x3e, 0x6f, 0xe6, 0xfd,
+	0x98, 0xf7, 0xbc, 0xe0, 0x32, 0xa1, 0x1e, 0xa1, 0x98, 0xea, 0x2d, 0xe2, 0xb7, 0x90, 0xcf, 0x02,
+	0x87, 0x21, 0xf7, 0x4a, 0x07, 0x3f, 0xec, 0x61, 0x17, 0xb3, 0xbe, 0xce, 0x1e, 0x69, 0xdd, 0x80,
+	0x30, 0x22, 0xbf, 0x11, 0x2b, 0x6a, 0xa3, 0x8a, 0x42, 0x4f, 0xdb, 0x36, 0x9a, 0x88, 0x39, 0x86,
+	0xb2, 0xd4, 0x26, 0x6d, 0x12, 0x21, 0xf4, 0xf0, 0x3f, 0x0e, 0x56, 0xd4, 0x36, 0x21, 0xed, 0x0e,
+	0xd2, 0xa3, 0x55, 0xb3, 0xb7, 0xa1, 0x33, 0xec, 0x21, 0xca, 0x1c, 0xaf, 0x1b, 0x2b, 0xd4, 0xb3,
+	0x0a, 0x6e, 0x2f, 0x70, 0x18, 0x26, 0x7e, 0xb2, 0xdf, 0x8a, 0xcc, 0xeb, 0x4d, 0x87, 0x22, 0x3d,
+	0xb6, 0xa5, 0xb7, 0x08, 0x8e, 0xf7, 0xe1, 0x2f, 0x15, 0xb0, 0xb0, 0x4e, 0xdb, 0xab, 0x01, 0x72,
+	0x18, 0xba, 0x4b, 0x28, 0x0e, 0xb1, 0xf2, 0xdb, 0x60, 0xaa, 0x4b, 0x48, 0xc7, 0xc6, 0x6e, 0x4d,
+	0x5a, 0x96, 0x56, 0x2a, 0xa6, 0x3c, 0x1c, 0xa8, 0xb3, 0x7d, 0xc7, 0xeb, 0xdc, 0x84, 0xf1, 0x06,
+	0xb4, 0x26, 0xc3, 0xff, 0x1a, 0xae, 0xfc, 0x16, 0x98, 0xa4, 0xc8, 0x77, 0x51, 0x50, 0x2b, 0x2d,
+	0x4b, 0x2b, 0xd3, 0xe6, 0xc2, 0x70, 0xa0, 0x56, 0xb9, 0x2e, 0x97, 0x43, 0x2b, 0x56, 0x90, 0xdf,
+	0x05, 0xa0, 0x43, 0x76, 0x50, 0x60, 0x33, 0xdc, 0xda, 0xaa, 0x95, 0x97, 0xa5, 0x95, 0xb2, 0x79,
+	0x76, 0x38, 0x50, 0x17, 0xb8, 0x7a, 0xba, 0x07, 0xad, 0xe9, 0x68, 0x71, 0x0f, 0xb7, 0xb6, 0x42,
+	0x54, 0xaf, 0xdb, 0x4d, 0x50, 0x95, 0x2c, 0x2a, 0xdd, 0x83, 0xd6, 0x74, 0xb4, 0x88, 0x50, 0x0c,
+	0xcc, 0x31, 0xb2, 0x85, 0x7c, 0x6a, 0x77, 0x03, 0xb2, 0x8d, 0x5d, 0xe4, 0xd6, 0x4e, 0x2d, 0x97,
+	0x57, 0x66, 0xae, 0x5d, 0xd0, 0xb8, 0x4f, 0xb4, 0xd0, 0x27, 0x89, 0xff, 0xb5, 0x55, 0x82, 0x7d,
+	0xf3, 0xea, 0xb3, 0x81, 0x3a, 0xf1, 0xd3, 0x0b, 0x75, 0xa5, 0x8d, 0xd9, 0x66, 0xaf, 0xa9, 0xb5,
+	0x88, 0xa7, 0xc7, 0x0e, 0xe4, 0x7f, 0xae, 0x50, 0x77, 0x4b, 0x67, 0xfd, 0x2e, 0xa2, 0x11, 0x80,
+	0x5a, 0xb3, 0xdc, 0xc6, 0xdd, 0xd8, 0x84, 0xbc, 0x0d, 0x16, 0x22, 0x89, 0xed, 0x61, 0xdf, 0x76,
+	0x3c, 0xd2, 0xf3, 0xd9, 0xd5, 0xda, 0x64, 0xe4, 0x97, 0x4f, 0x42, 0xf2, 0xdf, 0x07, 0xea, 0x9b,
+	0x87, 0x20, 0x6f, 0xf8, 0x6c, 0x38, 0x50, 0x6b, 0xfc, 0x82, 0x39, 0x42, 0x68, 0xf1, 0xab, 0xad,
+	0x63, 0xff, 0x36, 0x97, 0xec, 0x67, 0xd7, 0xa8, 0x4d, 0xbd, 0x5e, 0xbb, 0x46, 0xce, 0xae, 0x01,
+	0x9f, 0x55, 0xc0, 0x85, 0x5c, 0xfe, 0x58, 0x88, 0x76, 0x89, 0x4f, 0x91, 0xfc, 0x1e, 0x98, 0xe9,
+	0xc6, 0xb2, 0x34, 0x97, 0xce, 0x0d, 0x07, 0xaa, 0x9c, 0xe4, 0x92, 0xd8, 0x84, 0x16, 0x48, 0x56,
+	0x0d, 0x57, 0x7e, 0x00, 0xa6, 0x12, 0xe7, 0xf1, 0xa4, 0xba, 0x55, 0xf8, 0x12, 0x71, 0xba, 0x0a,
+	0x97, 0x25, 0x84, 0x29, 0xb7, 0x11, 0x65, 0xe0, 0x91, 0xb9, 0x0d, 0xc1, 0x6d, 0xc8, 0xf7, 0xc1,
+	0xf4, 0x17, 0x04, 0xfb, 0x76, 0x58, 0xa6, 0x51, 0xa6, 0xce, 0x5c, 0x53, 0x34, 0x5e, 0xa2, 0x5a,
+	0x52, 0xa2, 0xda, 0xbd, 0xa4, 0x86, 0xcd, 0x4b, 0xa1, 0xe5, 0xe1, 0x40, 0x9d, 0xe7, 0x7c, 0x02,
+	0x0a, 0x9f, 0xbe, 0x50, 0x25, 0xeb, 0x74, 0xb8, 0x0e, 0x95, 0xe5, 0x1d, 0xb0, 0x20, 0x5e, 0x0c,
+	0xbb, 0x15, 0xf9, 0x3a, 0xcc, 0xe6, 0xa2, 0xd1, 0x5d, 0x43, 0xad, 0x34, 0xba, 0x39, 0x42, 0x68,
+	0xcd, 0x0b, 0x19, 0x8f, 0xa7, 0x9b, 0x29, 0xd8, 0xc9, 0xb1, 0x0a, 0x76, 0xea, 0x70, 0x05, 0x0b,
+	0x7f, 0x2e, 0x81, 0xf9, 0x75, 0xda, 0xbe, 0xed, 0xba, 0xf7, 0x88, 0x78, 0x89, 0xc6, 0xce, 0xa0,
+	0x02, 0xaf, 0x92, 0x0d, 0x78, 0x15, 0xdb, 0x2e, 0xa2, 0x38, 0x40, 0xee, 0xd5, 0x28, 0x2f, 0xfe,
+	0xf5, 0xa1, 0xf8, 0x5f, 0x1c, 0xb8, 0xb3, 0xa3, 0x95, 0x92, 0xc0, 0xa1, 0x55, 0x8d, 0x04, 0x6b,
+	0xf1, 0x3a, 0x67, 0xc0, 0x88, 0x53, 0x63, 0x4c, 0x03, 0x46, 0xc6, 0x80, 0x01, 0xbf, 0x29, 0x81,
+	0x5a, 0xd6, 0x75, 0xff, 0xd9, 0x22, 0x84, 0x7f, 0x49, 0x60, 0x71, 0x9d, 0xb6, 0x3f, 0xc5, 0x6c,
+	0xd3, 0x0d, 0x9c, 0x9d, 0x13, 0xcd, 0x25, 0x06, 0xd2, 0x22, 0x8a, 0x9f, 0xcd, 0xf8, 0x82, 0x8d,
+	0xc2, 0x85, 0x7a, 0x3e, 0x5b, 0xa8, 0x9c, 0x0f, 0x5a, 0x73, 0x42, 0xc4, 0x9f, 0x61, 0xf8, 0xab,
+	0x04, 0x2e, 0xee, 0x73, 0x63, 0x91, 0x02, 0x23, 0x91, 0x94, 0x8e, 0x31, 0x92, 0xa5, 0xd7, 0x1d,
+	0xc9, 0x1d, 0x30, 0x1b, 0x36, 0x17, 0xd2, 0xe9, 0xa0, 0x16, 0xbb, 0x83, 0x10, 0x95, 0x6f, 0x82,
+	0x33, 0x23, 0x61, 0xa2, 0x35, 0x69, 0xb9, 0xbc, 0x52, 0x31, 0xcf, 0x0f, 0x07, 0xea, 0x62, 0x2e,
+	0x88, 0x14, 0x5a, 0x33, 0x69, 0x14, 0x69, 0x81, 0x30, 0xc2, 0x3e, 0x38, 0xb7, 0xd7, 0xb0, 0x70,
+	0xa5, 0x0d, 0x66, 0x5b, 0x5c, 0x8c, 0x5c, 0x7b, 0x03, 0x21, 0x7e, 0x84, 0x22, 0xb5, 0xbc, 0x17,
+	0x0e, 0xad, 0xaa, 0x10, 0x84, 0x86, 0xe0, 0x97, 0x60, 0x29, 0x35, 0xdd, 0x88, 0x46, 0x46, 0xbc,
+	0x7d, 0x72, 0x37, 0xff, 0xaa, 0x04, 0x2e, 0xed, 0x67, 0x5f, 0x38, 0xe0, 0x21, 0x58, 0x4a, 0x6f,
+	0x80, 0xc5, 0xfe, 0xab, 0xdd, 0xf0, 0xff, 0xd8, 0x0d, 0x17, 0xb3, 0x6e, 0x48, 0x49, 0xa0, 0xb5,
+	0x28, 0xc4, 0x23, 0x57, 0x7f, 0x08, 0x96, 0x36, 0x48, 0xb0, 0x81, 0x70, 0xc6, 0x64, 0xa9, 0xa0,
+	0xc9, 0xfd, 0x48, 0xa0, 0xb5, 0x28, 0xc4, 0xa9, 0x49, 0xf8, 0xb8, 0x02, 0x64, 0x31, 0xd7, 0x08,
+	0xf9, 0xb1, 0x0d, 0xc6, 0x36, 0x98, 0x15, 0x47, 0xb2, 0xc3, 0xf1, 0xbc, 0x70, 0x0b, 0xda, 0x0b,
+	0x87, 0x56, 0x55, 0x08, 0x42, 0x6d, 0x79, 0x0b, 0x54, 0x91, 0x87, 0x29, 0x0d, 0xf3, 0x23, 0xfc,
+	0x02, 0x89, 0x3a, 0xd0, 0xb4, 0x79, 0xa7, 0xf0, 0xa3, 0xb4, 0xc4, 0xcd, 0xed, 0x21, 0x83, 0xd6,
+	0x99, 0x64, 0x6d, 0x39, 0x0c, 0xc9, 0x9f, 0x01, 0x40, 0x99, 0x13, 0x30, 0x3e, 0x06, 0x9d, 0x7a,
+	0xe5, 0x18, 0x94, 0x5c, 0x25, 0x9e, 0x0f, 0x52, 0x2c, 0x9f, 0x83, 0xa6, 0x23, 0x41, 0x34, 0x08,
+	0x79, 0x00, 0x84, 0xf3, 0x68, 0xaf, 0x1b, 0x31, 0x4f, 0xc6, 0x3e, 0xca, 0x32, 0xaf, 0xc5, 0xdf,
+	0x40, 0xe6, 0xf5, 0x90, 0xf8, 0xcf, 0x81, 0x2a, 0x27, 0x5f, 0x45, 0xef, 0x10, 0x0f, 0x33, 0xe4,
+	0x75, 0x59, 0x3f, 0x35, 0x97, 0x12, 0xc2, 0x1f, 0x22, 0x73, 0x1e, 0xf6, 0xef, 0xf3, 0xf5, 0xdf,
+	0x65, 0xa0, 0xe4, 0xb3, 0x40, 0x94, 0xc2, 0x65, 0x30, 0x97, 0xba, 0xdd, 0x45, 0x3e, 0xf1, 0xf8,
+	0xf3, 0x6a, 0xa5, 0xc1, 0x5c, 0x0b, 0xa5, 0x61, 0x57, 0x48, 0x15, 0xe3, 0xae, 0x50, 0x3a, 0x5a,
+	0x57, 0xc8, 0xf2, 0x41, 0x2b, 0x3d, 0x0b, 0xef, 0x0a, 0xf9, 0x98, 0x97, 0x4f, 0x2c, 0xe6, 0x95,
+	0x63, 0x8b, 0xf9, 0xa9, 0xe3, 0x8e, 0xf9, 0x63, 0x29, 0x8a, 0xf9, 0x9d, 0x9e, 0xdf, 0xc6, 0x1b,
+	0xfd, 0xd5, 0x4d, 0x27, 0x68, 0x23, 0x37, 0xe9, 0xa8, 0x27, 0xf6, 0x0c, 0x6f, 0x02, 0x78, 0xf0,
+	0x21, 0x44, 0x02, 0x9a, 0x60, 0xce, 0x47, 0x3b, 0x76, 0x7e, 0xaa, 0x51, 0x86, 0x03, 0xf5, 0x1c,
+	0x67, 0xce, 0x28, 0x40, 0xab, 0xea, 0x23, 0x31, 0x21, 0x34, 0xdc, 0x6b, 0x4f, 0x4e, 0x83, 0xf2,
+	0x3a, 0x6d, 0xcb, 0xdf, 0x4a, 0x60, 0x36, 0xf3, 0x33, 0xc0, 0xfb, 0xda, 0xa1, 0x7e, 0xbb, 0xd0,
+	0x72, 0x1f, 0x80, 0xca, 0xad, 0x71, 0x91, 0xe2, 0x6a, 0xdf, 0x49, 0x60, 0x3e, 0x37, 0xc1, 0xdd,
+	0x3c, 0x3c, 0x6d, 0x16, 0xab, 0x98, 0xe3, 0x63, 0xc5, 0xa1, 0xbe, 0x96, 0x40, 0x35, 0xf3, 0x7d,
+	0x72, 0x78, 0xd6, 0x3d, 0x40, 0xe5, 0xe3, 0x31, 0x81, 0xe2, 0x2c, 0x8f, 0x25, 0x30, 0x33, 0x3a,
+	0x19, 0xdd, 0x28, 0xe0, 0xf2, 0x14, 0xa6, 0x7c, 0x34, 0x16, 0x4c, 0x9c, 0xe2, 0x7b, 0x09, 0x2c,
+	0xe4, 0x67, 0x95, 0x0f, 0x0b, 0x93, 0xa6, 0x60, 0x65, 0xf5, 0x08, 0x60, 0x71, 0xae, 0x27, 0x12,
+	0x98, 0xcb, 0x36, 0xef, 0x0f, 0x8a, 0x26, 0xa5, 0x80, 0x2a, 0xb7, 0xc7, 0x86, 0x8a, 0x13, 0xfd,
+	0x28, 0x81, 0xf3, 0x07, 0x3d, 0x2a, 0x05, 0xe8, 0x0f, 0xa0, 0x50, 0x1a, 0x47, 0xa6, 0x48, 0x4e,
+	0x6a, 0x7e, 0xfe, 0xec, 0x65, 0x5d, 0x7a, 0xfe, 0xb2, 0x2e, 0xfd, 0xf1, 0xb2, 0x2e, 0x3d, 0xdd,
+	0xad, 0x4f, 0x3c, 0xdf, 0xad, 0x4f, 0xfc, 0xb6, 0x5b, 0x9f, 0x78, 0x60, 0x8e, 0xb4, 0x8c, 0xd8,
+	0xdc, 0x95, 0x8e, 0xd3, 0xa4, 0xc9, 0x42, 0xdf, 0x36, 0x6e, 0xe8, 0x8f, 0x0e, 0xfc, 0x49, 0x34,
+	0x6c, 0x29, 0xcd, 0xc9, 0xe8, 0xc9, 0xbe, 0xfe, 0x4f, 0x00, 0x00, 0x00, 0xff, 0xff, 0xe3, 0xe6,
+	0x38, 0xf7, 0x41, 0x15, 0x00, 0x00,
 }
 
 // Reference imports to suppress errors if they are not otherwise used.
@@ -1320,6 +1341,16 @@ func (m *MsgCreatePositionResponse) MarshalToSizedBuffer(dAtA []byte) (int, erro
 	_ = i
 	var l int
 	_ = l
+	if m.UpperTick != 0 {
+		i = encodeVarintTx(dAtA, i, uint64(m.UpperTick))
+		i--
+		dAtA[i] = 0x38
+	}
+	if m.LowerTick != 0 {
+		i = encodeVarintTx(dAtA, i, uint64(m.LowerTick))
+		i--
+		dAtA[i] = 0x30
+	}
 	{
 		size := m.LiquidityCreated.Size()
 		i -= size
@@ -2014,6 +2045,12 @@ func (m *MsgCreatePositionResponse) Size() (n int) {
 	n += 1 + l + sovTx(uint64(l))
 	l = m.LiquidityCreated.Size()
 	n += 1 + l + sovTx(uint64(l))
+	if m.LowerTick != 0 {
+		n += 1 + sovTx(uint64(m.LowerTick))
+	}
+	if m.UpperTick != 0 {
+		n += 1 + sovTx(uint64(m.UpperTick))
+	}
 	return n
 }
 
@@ -2667,6 +2704,44 @@ func (m *MsgCreatePositionResponse) Unmarshal(dAtA []byte) error {
 				return err
 			}
 			iNdEx = postIndex
+		case 6:
+			if wireType != 0 {
+				return fmt.Errorf("proto: wrong wireType = %d for field LowerTick", wireType)
+			}
+			m.LowerTick = 0
+			for shift := uint(0); ; shift += 7 {
+				if shift >= 64 {
+					return ErrIntOverflowTx
+				}
+				if iNdEx >= l {
+					return io.ErrUnexpectedEOF
+				}
+				b := dAtA[iNdEx]
+				iNdEx++
+				m.LowerTick |= int64(b&0x7F) << shift
+				if b < 0x80 {
+					break
+				}
+			}
+		case 7:
+			if wireType != 0 {
+				return fmt.Errorf("proto: wrong wireType = %d for field UpperTick", wireType)
+			}
+			m.UpperTick = 0
+			for shift := uint(0); ; shift += 7 {
+				if shift >= 64 {
+					return ErrIntOverflowTx
+				}
+				if iNdEx >= l {
+					return io.ErrUnexpectedEOF
+				}
+				b := dAtA[iNdEx]
+				iNdEx++
+				m.UpperTick |= int64(b&0x7F) << shift
+				if b < 0x80 {
+					break
+				}
+			}
 		default:
 			iNdEx = preIndex
 			skippy, err := skipTx(dAtA[iNdEx:])
diff --git a/x/gamm/types/key.go b/x/gamm/types/key.go
index 36a004213..ebfea87e4 100644
--- a/x/gamm/types/key.go
+++ b/x/gamm/types/key.go
@@ -33,11 +33,12 @@ var (
 )
 
 func MustGetPoolIdFromShareDenom(denom string) uint64 {
-	number, err := GetPoolIdFromShareDenom(denom)
+	numberStr := strings.TrimLeft(denom, GAMMTokenPrefix)
+	number, err := strconv.Atoi(numberStr)
 	if err != nil {
 		panic(err)
 	}
-	return number
+	return uint64(number)
 }
 
 func GetPoolIdFromShareDenom(denom string) (uint64, error) {
diff --git a/x/superfluid/README.md b/x/superfluid/README.md
index b283ef7e4..8ff1f497b 100644
--- a/x/superfluid/README.md
+++ b/x/superfluid/README.md
@@ -376,41 +376,6 @@ It then mints concentrated liquidity shares and locks them up for the
 staking duration. From there, the normal superfluid delegation logic
 is executed.
 
-### Create Full Range Position and Superfluid Delegate
-
-```{.go}
-type MsgUnlockAndMigrateSharesToFullRangeConcentratedPosition struct {
- Sender string
- LockId uint64
- SharesToMigrate sdk.Coin
- TokenOutMins sdk.Coins
-}
-```
-
-Upon completion, the following response is given:
-
-```{.go}
-type MsgUnlockAndMigrateSharesToFullRangeConcentratedPositionResponse struct {
- Amount0 string
- Amount1 string
- LiquidityCreated sdk.Dec
- JoinTime time.Time
-}
-```
-
-The message starts by determining which migration method to use.
-- If underlying lock is superfluid bonded
-  - `migrateSuperfluidBondedBalancerToConcentrated`
-- If underlying lock is superfluid unbonding
-  - `migrateSuperfluidUnbondingBalancerToConcentrated`
-- If underlying lock is not superfluid bonded (vanilla lock)
-  - `migrateNonSuperfluidLockBalancerToConcentrated`
-
-It then routes to that migration message, which will migrate the gamm lock from
-the previous state it was in, to the same state but in the concentrated pool. If
-the sharesToMigrate is zero, then the entire lock is migrated. If only a subset
-of the shares are migrated, then the remaining shares are left in the gamm pool.
-
 ## Epochs
 
 Overall Epoch sequence
diff --git a/x/superfluid/client/cli/tx.go b/x/superfluid/client/cli/tx.go
index bb3f0de64..6f7e38137 100644
--- a/x/superfluid/client/cli/tx.go
+++ b/x/superfluid/client/cli/tx.go
@@ -37,7 +37,6 @@ func GetTxCmd() *cobra.Command {
 	)
 	osmocli.AddTxCmd(cmd, NewCreateFullRangePositionAndSuperfluidDelegateCmd)
 	osmocli.AddTxCmd(cmd, NewAddToConcentratedLiquiditySuperfluidPositionCmd)
-	osmocli.AddTxCmd(cmd, NewUnlockAndMigrateSharesToFullRangeConcentratedPositionCmd)
 
 	return cmd
 }
@@ -415,11 +414,3 @@ func NewAddToConcentratedLiquiditySuperfluidPositionCmd() (*osmocli.TxCliDesc, *
 		Example: "add-to-superfluid-cl-position 10 1000000000uosmo 10000000uion",
 	}, &types.MsgAddToConcentratedLiquiditySuperfluidPosition{}
 }
-
-func NewUnlockAndMigrateSharesToFullRangeConcentratedPositionCmd() (*osmocli.TxCliDesc, *types.MsgUnlockAndMigrateSharesToFullRangeConcentratedPosition) {
-	return &osmocli.TxCliDesc{
-		Use:     "unlock-and-migrate-to-cl [lock-id] [shares-to-migrate] [token-out-mins]",
-		Short:   "unlock and migrate gamm shares to full range concentrated position",
-		Example: "unlock-and-migrate-cl 10 25000000000gamm/pool/2 1000000000uosmo,10000000uion",
-	}, &types.MsgUnlockAndMigrateSharesToFullRangeConcentratedPosition{}
-}
diff --git a/x/superfluid/keeper/concentrated_liquidity.go b/x/superfluid/keeper/concentrated_liquidity.go
index bdba4278d..0a2085831 100644
--- a/x/superfluid/keeper/concentrated_liquidity.go
+++ b/x/superfluid/keeper/concentrated_liquidity.go
@@ -69,7 +69,7 @@ func (k Keeper) addToConcentratedLiquiditySuperfluidPosition(ctx sdk.Context, ow
 
 	// Superfluid undelegate the superfluid delegated position.
 	// This deletes the connection between the lock and the intermediate account, deletes the synthetic lock, and burns the synthetic osmo.
-	intermediateAccount, err := k.superfluidUndelegateToConcentratedPosition(ctx, owner.String(), lockId)
+	intermediateAccount, err := k.SuperfluidUndelegateToConcentratedPosition(ctx, owner.String(), lockId)
 	if err != nil {
 		return 0, sdk.Int{}, sdk.Int{}, sdk.Dec{}, 0, err
 	}
diff --git a/x/superfluid/keeper/migrate.go b/x/superfluid/keeper/migrate.go
index a505605d4..b9a5ea10f 100644
--- a/x/superfluid/keeper/migrate.go
+++ b/x/superfluid/keeper/migrate.go
@@ -66,7 +66,7 @@ func (k Keeper) migrateSuperfluidBondedBalancerToConcentrated(ctx sdk.Context,
 
 	// Superfluid undelegate the superfluid delegated position.
 	// This deletes the connection between the lock and the intermediate account, deletes the synthetic lock, and burns the synthetic osmo.
-	intermediateAccount, err := k.superfluidUndelegateToConcentratedPosition(ctx, sender.String(), lockId)
+	intermediateAccount, err := k.SuperfluidUndelegateToConcentratedPosition(ctx, sender.String(), lockId)
 	if err != nil {
 		return 0, sdk.Int{}, sdk.Int{}, sdk.Dec{}, time.Time{}, 0, 0, err
 	}
@@ -286,16 +286,13 @@ func (k Keeper) prepareMigration(ctx sdk.Context, sender sdk.AccAddress, lockId
 	}
 
 	// Check that lockID corresponds to sender, and contains correct denomination of LP shares.
-	preMigrationLock, err = k.validateGammLockForSuperfluidStaking(ctx, sender, poolIdLeaving, lockId)
+	preMigrationLock, err = k.validateLockForUnpool(ctx, sender, poolIdLeaving, lockId)
 	if err != nil {
 		return 0, 0, nil, &lockuptypes.PeriodLock{}, 0, nil, false, false, err
 	}
 
 	// Before we break the lock, we must note the time remaining on the lock.
-	remainingLockTime, err = k.getExistingLockRemainingDuration(ctx, preMigrationLock)
-	if err != nil {
-		return 0, 0, nil, &lockuptypes.PeriodLock{}, 0, nil, false, false, err
-	}
+	remainingLockTime = k.getExistingLockRemainingDuration(ctx, preMigrationLock)
 
 	// Check if the lock has a corresponding synthetic lock.
 	// Synthetic lock existence implies that the lock is superfluid delegated or undelegating.
diff --git a/x/superfluid/keeper/msg_server.go b/x/superfluid/keeper/msg_server.go
index cded0c8ea..7b9a8339e 100644
--- a/x/superfluid/keeper/msg_server.go
+++ b/x/superfluid/keeper/msg_server.go
@@ -132,6 +132,38 @@ func (server msgServer) LockAndSuperfluidDelegate(goCtx context.Context, msg *ty
 	}, err
 }
 
+func (server msgServer) CreateFullRangePositionAndSuperfluidDelegate(goCtx context.Context, msg *types.MsgCreateFullRangePositionAndSuperfluidDelegate) (*types.MsgCreateFullRangePositionAndSuperfluidDelegateResponse, error) {
+	ctx := sdk.UnwrapSDKContext(goCtx)
+
+	address, err := sdk.AccAddressFromBech32(msg.Sender)
+	if err != nil {
+		return &types.MsgCreateFullRangePositionAndSuperfluidDelegateResponse{}, err
+	}
+	positionId, _, _, _, _, lockId, err := server.keeper.clk.CreateFullRangePositionLocked(ctx, msg.PoolId, address, msg.Coins, server.keeper.sk.GetParams(ctx).UnbondingTime)
+	if err != nil {
+		return &types.MsgCreateFullRangePositionAndSuperfluidDelegateResponse{}, err
+	}
+
+	superfluidDelegateMsg := types.MsgSuperfluidDelegate{
+		Sender:  msg.Sender,
+		LockId:  lockId,
+		ValAddr: msg.ValAddr,
+	}
+
+	_, err = server.SuperfluidDelegate(goCtx, &superfluidDelegateMsg)
+
+	if err != nil {
+		return &types.MsgCreateFullRangePositionAndSuperfluidDelegateResponse{}, err
+	}
+
+	events.EmitCreateFullRangePositionAndSuperfluidDelegateEvent(ctx, lockId, positionId, msg.ValAddr)
+
+	return &types.MsgCreateFullRangePositionAndSuperfluidDelegateResponse{
+		LockID:     lockId,
+		PositionID: positionId,
+	}, nil
+}
+
 func (server msgServer) UnPoolWhitelistedPool(goCtx context.Context, msg *types.MsgUnPoolWhitelistedPool) (*types.MsgUnPoolWhitelistedPoolResponse, error) {
 	ctx := sdk.UnwrapSDKContext(goCtx)
 
@@ -165,38 +197,6 @@ func (server msgServer) UnPoolWhitelistedPool(goCtx context.Context, msg *types.
 	return &types.MsgUnPoolWhitelistedPoolResponse{ExitedLockIds: allExitedLockIDs}, nil
 }
 
-func (server msgServer) CreateFullRangePositionAndSuperfluidDelegate(goCtx context.Context, msg *types.MsgCreateFullRangePositionAndSuperfluidDelegate) (*types.MsgCreateFullRangePositionAndSuperfluidDelegateResponse, error) {
-	ctx := sdk.UnwrapSDKContext(goCtx)
-
-	address, err := sdk.AccAddressFromBech32(msg.Sender)
-	if err != nil {
-		return &types.MsgCreateFullRangePositionAndSuperfluidDelegateResponse{}, err
-	}
-	positionId, _, _, _, _, lockId, err := server.keeper.clk.CreateFullRangePositionLocked(ctx, msg.PoolId, address, msg.Coins, server.keeper.sk.GetParams(ctx).UnbondingTime)
-	if err != nil {
-		return &types.MsgCreateFullRangePositionAndSuperfluidDelegateResponse{}, err
-	}
-
-	superfluidDelegateMsg := types.MsgSuperfluidDelegate{
-		Sender:  msg.Sender,
-		LockId:  lockId,
-		ValAddr: msg.ValAddr,
-	}
-
-	_, err = server.SuperfluidDelegate(goCtx, &superfluidDelegateMsg)
-
-	if err != nil {
-		return &types.MsgCreateFullRangePositionAndSuperfluidDelegateResponse{}, err
-	}
-
-	events.EmitCreateFullRangePositionAndSuperfluidDelegateEvent(ctx, lockId, positionId, msg.ValAddr)
-
-	return &types.MsgCreateFullRangePositionAndSuperfluidDelegateResponse{
-		LockID:     lockId,
-		PositionID: positionId,
-	}, nil
-}
-
 func (server msgServer) UnlockAndMigrateSharesToFullRangeConcentratedPosition(goCtx context.Context, msg *types.MsgUnlockAndMigrateSharesToFullRangeConcentratedPosition) (*types.MsgUnlockAndMigrateSharesToFullRangeConcentratedPositionResponse, error) {
 	ctx := sdk.UnwrapSDKContext(goCtx)
 
diff --git a/x/superfluid/keeper/stake.go b/x/superfluid/keeper/stake.go
index 64dfcb276..d643ce94c 100644
--- a/x/superfluid/keeper/stake.go
+++ b/x/superfluid/keeper/stake.go
@@ -242,7 +242,7 @@ func (k Keeper) SuperfluidDelegate(ctx sdk.Context, sender string, lockID uint64
 	return k.mintOsmoTokensAndDelegate(ctx, amount, acc)
 }
 
-// undelegateCommon is a helper function for SuperfluidUndelegate and superfluidUndelegateToConcentratedPosition.
+// undelegateCommon is a helper function for SuperfluidUndelegate and SuperfluidUndelegateToConcentratedPosition.
 // It performs the following tasks:
 // - checks that the lock is valid for superfluid staking
 // - gets the intermediary account associated with the lock id
@@ -300,10 +300,10 @@ func (k Keeper) SuperfluidUndelegate(ctx sdk.Context, sender string, lockID uint
 	return k.createSyntheticLockup(ctx, lockID, intermediaryAcc, unlockingStatus)
 }
 
-// superfluidUndelegateToConcentratedPosition starts undelegating superfluid delegated position for the given lock. It behaves similarly to SuperfluidUndelegate,
+// SuperfluidUndelegateToConcentratedPosition starts undelegating superfluid delegated position for the given lock. It behaves similarly to SuperfluidUndelegate,
 // however it does not create a new synthetic lockup representing the unstaking side. This is because at the time this function is called, the new concentrated liquidity side
 // lock has not yet been created. Once the new cl side lock is created, the synthetic lockup representing the unstaking side is created.
-func (k Keeper) superfluidUndelegateToConcentratedPosition(ctx sdk.Context, sender string, gammLockID uint64) (types.SuperfluidIntermediaryAccount, error) {
+func (k Keeper) SuperfluidUndelegateToConcentratedPosition(ctx sdk.Context, sender string, gammLockID uint64) (types.SuperfluidIntermediaryAccount, error) {
 	return k.undelegateCommon(ctx, sender, gammLockID)
 }
 
diff --git a/x/superfluid/keeper/unpool.go b/x/superfluid/keeper/unpool.go
index f2be67e16..0f3dfadc4 100644
--- a/x/superfluid/keeper/unpool.go
+++ b/x/superfluid/keeper/unpool.go
@@ -33,17 +33,14 @@ func (k Keeper) UnpoolAllowedPools(ctx sdk.Context, sender sdk.AccAddress, poolI
 	// 2) Consistency check that lockID corresponds to sender, and contains correct LP shares.
 	// These are expected to be true by the caller, but good to double check
 	// TODO: Try to minimize dependence on lock here
-	lock, err := k.validateGammLockForSuperfluidStaking(ctx, sender, poolId, lockId)
+	lock, err := k.validateLockForUnpool(ctx, sender, poolId, lockId)
 	if err != nil {
 		return []uint64{}, err
 	}
 	gammSharesInLock := lock.Coins[0]
 
 	// 3) Get remaining duration on the lock. Handle if the lock was unbonding.
-	lockRemainingDuration, err := k.getExistingLockRemainingDuration(ctx, lock)
-	if err != nil {
-		return []uint64{}, err
-	}
+	lockRemainingDuration := k.getExistingLockRemainingDuration(ctx, lock)
 
 	// 4) If superfluid delegated, superfluid undelegate
 	err = k.unbondSuperfluidIfExists(ctx, sender, lockId)
@@ -102,48 +99,39 @@ func (k Keeper) checkUnpoolWhitelisted(ctx sdk.Context, poolId uint64) error {
 	return types.ErrPoolNotWhitelisted
 }
 
-// validateGammLockForSuperfluidStaking checks if the provided lock:
-// 1) is owned by the provided sender
-// 2) contains only 1 coin
-// 3) contains the gamm LP shares associated with the provided poolId
-func (k Keeper) validateGammLockForSuperfluidStaking(ctx sdk.Context, sender sdk.AccAddress, poolId uint64, lockId uint64) (*lockuptypes.PeriodLock, error) {
+// check if pool is whitelisted for unpool
+func (k Keeper) validateLockForUnpool(ctx sdk.Context, sender sdk.AccAddress, poolId uint64, lockId uint64) (*lockuptypes.PeriodLock, error) {
 	lock, err := k.lk.GetLockByID(ctx, lockId)
 	if err != nil {
-		return &lockuptypes.PeriodLock{}, err
+		return lock, err
 	}
 
-	// Validate lock owner.
-	// We expect this to be guaranteed by caller, though.
+	// consistency check: validate lock owner
+	// However, we expect this to be guaranteed by caller though.
 	if lock.Owner != sender.String() {
-		return &lockuptypes.PeriodLock{}, lockuptypes.ErrNotLockOwner
+		return lock, lockuptypes.ErrNotLockOwner
 	}
 
 	if lock.Coins.Len() != 1 {
-		return &lockuptypes.PeriodLock{}, types.ErrMultipleCoinsLockupNotSupported
+		return lock, types.ErrMultipleCoinsLockupNotSupported
 	}
 
 	gammShare := lock.Coins[0]
 	if gammShare.Denom != gammtypes.GetPoolShareDenom(poolId) {
-		return &lockuptypes.PeriodLock{}, types.UnexpectedDenomError{ExpectedDenom: gammtypes.GetPoolShareDenom(poolId), ProvidedDenom: gammShare.Denom}
+		return lock, types.ErrLockUnpoolNotAllowed
 	}
 
 	return lock, nil
 }
 
-// getExistingLockRemainingDuration returns the time remaining until the lock is finished unlocking.
-// If the lock is not unlocking, then the duration field of the lock is returned.
-func (k Keeper) getExistingLockRemainingDuration(ctx sdk.Context, lock *lockuptypes.PeriodLock) (time.Duration, error) {
+func (k Keeper) getExistingLockRemainingDuration(ctx sdk.Context, lock *lockuptypes.PeriodLock) time.Duration {
 	if lock.IsUnlocking() {
-		// Lock is unlocking, so remaining duration equals lock.EndTime - ctx.BlockTime.
+		// lock is unlocking, so remaining duration equals lock.EndTime - ctx.BlockTime
 		remainingDuration := lock.EndTime.Sub(ctx.BlockTime())
-		// Defense in depth, ensure the duration is not negative.
-		if remainingDuration < 0 {
-			return 0, types.NegativeDurationError{Duration: remainingDuration}
-		}
-		return remainingDuration, nil
+		return remainingDuration
 	}
-	// Lock is not unlocking, thus the time it should take to unlock is the locks duration.
-	return lock.Duration, nil
+	// lock is bonded, thus the time it should take to unlock is lock.Duration
+	return lock.Duration
 }
 
 // TODO: Review this in more depth
diff --git a/x/superfluid/types/errors.go b/x/superfluid/types/errors.go
index 27db450f7..45f8c886c 100644
--- a/x/superfluid/types/errors.go
+++ b/x/superfluid/types/errors.go
@@ -2,7 +2,6 @@ package types
 
 import (
 	fmt "fmt"
-	"time"
 
 	errorsmod "cosmossdk.io/errors"
 )
@@ -52,20 +51,3 @@ type LockOwnerMismatchError struct {
 func (e LockOwnerMismatchError) Error() string {
 	return fmt.Sprintf("lock ID %d owner %s does not match provided owner %s.", e.LockId, e.LockOwner, e.ProvidedOwner)
 }
-
-type NegativeDurationError struct {
-	Duration time.Duration
-}
-
-func (e NegativeDurationError) Error() string {
-	return fmt.Sprintf("duration cannot be negative (%s)", e.Duration)
-}
-
-type UnexpectedDenomError struct {
-	ExpectedDenom string
-	ProvidedDenom string
-}
-
-func (e UnexpectedDenomError) Error() string {
-	return fmt.Sprintf("provided denom (%s) was expected to be formatted as follows: %s", e.ProvidedDenom, e.ExpectedDenom)
-}
diff --git a/x/superfluid/types/tx.pb.go b/x/superfluid/types/tx.pb.go
index ecd488224..786cc740f 100644
--- a/x/superfluid/types/tx.pb.go
+++ b/x/superfluid/types/tx.pb.go
@@ -766,7 +766,7 @@ type MsgUnlockAndMigrateSharesToFullRangeConcentratedPosition struct {
 	LockId          uint64     `protobuf:"varint,2,opt,name=lock_id,json=lockId,proto3" json:"lock_id,omitempty" yaml:"lock_id"`
 	SharesToMigrate types.Coin `protobuf:"bytes,3,opt,name=shares_to_migrate,json=sharesToMigrate,proto3" json:"shares_to_migrate" yaml:"shares_to_migrate"`
 	// token_out_mins indicates minimum token to exit Balancer pool with.
-	TokenOutMins github_com_cosmos_cosmos_sdk_types.Coins `protobuf:"bytes,4,rep,name=token_out_mins,json=tokenOutMins,proto3,castrepeated=github.com/cosmos/cosmos-sdk/types.Coins" json:"token_out_mins" yaml:"token_out_mins"`
+	TokenOutMins []types.Coin `protobuf:"bytes,4,rep,name=token_out_mins,json=tokenOutMins,proto3" json:"token_out_mins" yaml:"token_out_min_amounts"`
 }
 
 func (m *MsgUnlockAndMigrateSharesToFullRangeConcentratedPosition) Reset() {
@@ -827,7 +827,7 @@ func (m *MsgUnlockAndMigrateSharesToFullRangeConcentratedPosition) GetSharesToMi
 	return types.Coin{}
 }
 
-func (m *MsgUnlockAndMigrateSharesToFullRangeConcentratedPosition) GetTokenOutMins() github_com_cosmos_cosmos_sdk_types.Coins {
+func (m *MsgUnlockAndMigrateSharesToFullRangeConcentratedPosition) GetTokenOutMins() []types.Coin {
 	if m != nil {
 		return m.TokenOutMins
 	}
@@ -1040,80 +1040,81 @@ func init() {
 func init() { proto.RegisterFile("osmosis/superfluid/tx.proto", fileDescriptor_55b645f187d22814) }
 
 var fileDescriptor_55b645f187d22814 = []byte{
-	// 1168 bytes of a gzipped FileDescriptorProto
-	0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xd4, 0x58, 0x4f, 0x4f, 0x1b, 0x47,
-	0x14, 0x67, 0x6d, 0x17, 0x92, 0xa1, 0x21, 0x61, 0x1b, 0x12, 0xe3, 0x26, 0x5e, 0x67, 0x5a, 0x45,
-	0x54, 0x21, 0xbb, 0x98, 0x34, 0x01, 0xf5, 0x04, 0xc6, 0x6a, 0xe5, 0x14, 0xab, 0x68, 0x03, 0xaa,
-	0x14, 0xa9, 0xb2, 0xd6, 0x9e, 0xc9, 0xb2, 0x65, 0xbd, 0xe3, 0xec, 0x8c, 0x29, 0xa8, 0x1f, 0x20,
-	0x55, 0x4f, 0xf9, 0x06, 0xbd, 0xf7, 0xd0, 0xcf, 0xd0, 0x5b, 0xa3, 0x9e, 0x72, 0x6b, 0xd5, 0x4a,
-	0x4e, 0x05, 0xdf, 0x80, 0x63, 0x4f, 0xd5, 0xec, 0xce, 0x8e, 0x6d, 0xf0, 0x62, 0xd6, 0x71, 0x0e,
-	0x3d, 0xb1, 0x33, 0xef, 0xbd, 0xdf, 0xfb, 0xff, 0xe6, 0x61, 0xf0, 0x21, 0xa1, 0x4d, 0x42, 0x1d,
-	0x6a, 0xd0, 0x76, 0x0b, 0xfb, 0xcf, 0xdc, 0xb6, 0x83, 0x0c, 0x76, 0xa0, 0xb7, 0x7c, 0xc2, 0x88,
-	0xaa, 0x0a, 0xa2, 0xde, 0x25, 0xe6, 0xae, 0xdb, 0xc4, 0x26, 0x01, 0xd9, 0xe0, 0x5f, 0x21, 0x67,
-	0x2e, 0x6f, 0x13, 0x62, 0xbb, 0xd8, 0x08, 0x4e, 0xf5, 0xf6, 0x33, 0x03, 0xb5, 0x7d, 0x8b, 0x39,
-	0xc4, 0x8b, 0xe8, 0x8d, 0x00, 0xca, 0xa8, 0x5b, 0x14, 0x1b, 0xfb, 0xc5, 0x3a, 0x66, 0x56, 0xd1,
-	0x68, 0x10, 0x27, 0xa2, 0x6b, 0xa7, 0xe5, 0x99, 0xd3, 0xc4, 0x94, 0x59, 0xcd, 0x96, 0x60, 0xf8,
-	0x68, 0x80, 0x9d, 0xdd, 0xcf, 0x90, 0x09, 0xee, 0x83, 0xb9, 0x2a, 0xb5, 0x9f, 0xc8, 0xeb, 0x32,
-	0x76, 0xb1, 0x6d, 0x31, 0xac, 0x7e, 0x02, 0x26, 0x29, 0xf6, 0x10, 0xf6, 0xb3, 0x4a, 0x41, 0x59,
-	0xb8, 0x5c, 0x9a, 0x3d, 0xe9, 0x68, 0x57, 0x0e, 0xad, 0xa6, 0xfb, 0x19, 0x0c, 0xef, 0xa1, 0x29,
-	0x18, 0xd4, 0x9b, 0x60, 0xca, 0x25, 0x8d, 0xbd, 0x9a, 0x83, 0xb2, 0xa9, 0x82, 0xb2, 0x90, 0x31,
-	0x27, 0xf9, 0xb1, 0x82, 0xd4, 0x79, 0x70, 0x69, 0xdf, 0x72, 0x6b, 0x16, 0x42, 0x7e, 0x36, 0xcd,
-	0x51, 0xcc, 0xa9, 0x7d, 0xcb, 0x5d, 0x47, 0xc8, 0x87, 0x1a, 0xb8, 0x3d, 0x50, 0xaf, 0x89, 0x69,
-	0x8b, 0x78, 0x14, 0xc3, 0x6f, 0xc0, 0xcd, 0x3e, 0x86, 0x1d, 0x0f, 0x8d, 0xd1, 0x34, 0x78, 0x07,
-	0x68, 0x31, 0xf0, 0xe7, 0x58, 0x50, 0x27, 0x1e, 0xda, 0x24, 0x8d, 0xbd, 0x77, 0x64, 0x41, 0x04,
-	0x2f, 0x2d, 0xf8, 0x45, 0x01, 0x1f, 0xc7, 0x58, 0xb9, 0xee, 0x8d, 0xd9, 0x1e, 0xb5, 0x04, 0x32,
-	0xbc, 0xba, 0x82, 0x44, 0x4d, 0x2f, 0xcf, 0xeb, 0x61, 0xf9, 0xe9, 0xbc, 0xfc, 0x74, 0x51, 0x7e,
-	0xfa, 0x06, 0x71, 0xbc, 0xd2, 0x07, 0xaf, 0x3a, 0xda, 0xc4, 0x49, 0x47, 0x9b, 0x0e, 0x15, 0x70,
-	0x21, 0x68, 0x06, 0xb2, 0xf0, 0x0b, 0xb0, 0x78, 0x11, 0x7b, 0x23, 0x07, 0x7b, 0x8d, 0x51, 0xfa,
-	0x82, 0xf3, 0x9b, 0x02, 0x6e, 0x55, 0xa9, 0xcd, 0x99, 0xd7, 0x3d, 0xf4, 0x76, 0xe5, 0x69, 0x81,
-	0xf7, 0xb8, 0x71, 0x34, 0x9b, 0x2a, 0xa4, 0xcf, 0xf7, 0x6c, 0x89, 0x7b, 0xf6, 0xf3, 0x1b, 0x6d,
-	0xc1, 0x76, 0xd8, 0x6e, 0xbb, 0xae, 0x37, 0x48, 0xd3, 0x10, 0x5d, 0x18, 0xfe, 0xb9, 0x4f, 0xd1,
-	0x9e, 0xc1, 0x0e, 0x5b, 0x98, 0x06, 0x02, 0xd4, 0x0c, 0x91, 0xcf, 0x2b, 0xf4, 0x47, 0x41, 0x0a,
-	0x63, 0x1d, 0x91, 0xa1, 0x98, 0x01, 0xa9, 0x4a, 0x59, 0x44, 0x21, 0x55, 0x29, 0xc3, 0x17, 0x29,
-	0x60, 0x54, 0xa9, 0xbd, 0xe1, 0x63, 0x8b, 0xe1, 0xcf, 0xdb, 0xae, 0x6b, 0x5a, 0x9e, 0x8d, 0xb7,
-	0x08, 0x75, 0xf8, 0x8c, 0xf8, 0x7f, 0x07, 0x45, 0xbd, 0x07, 0xa6, 0x5a, 0x84, 0xb8, 0x3c, 0xef,
-	0x19, 0xee, 0x71, 0x49, 0x3d, 0xe9, 0x68, 0x33, 0xa1, 0xa5, 0x82, 0x00, 0xcd, 0x49, 0xfe, 0x55,
-	0x41, 0xf0, 0x39, 0x58, 0x49, 0x18, 0x08, 0x19, 0xd4, 0x1b, 0x20, 0x2c, 0xa8, 0x72, 0x5f, 0x79,
-	0x95, 0xd5, 0x3c, 0x00, 0x2d, 0x01, 0x50, 0x29, 0x8b, 0x3e, 0xe8, 0xb9, 0x81, 0x3e, 0xc8, 0x56,
-	0xa9, 0xbd, 0xe3, 0x6d, 0x11, 0xe2, 0x7e, 0xbd, 0xeb, 0x30, 0xec, 0x3a, 0x94, 0x61, 0xc4, 0x8f,
-	0x49, 0x82, 0xdc, 0xe3, 0x66, 0x6a, 0xa8, 0x9b, 0x8f, 0x41, 0x21, 0x4e, 0xa7, 0xf4, 0xe7, 0x2e,
-	0xb8, 0x8a, 0x0f, 0x1c, 0x86, 0x51, 0x4d, 0xb4, 0x0d, 0xcd, 0x2a, 0x85, 0xf4, 0x42, 0xc6, 0xbc,
-	0x12, 0x5e, 0x6f, 0x06, 0xdd, 0x43, 0xe1, 0x0f, 0x69, 0xb0, 0x1a, 0x80, 0xb9, 0x61, 0xdd, 0x55,
-	0x1d, 0xdb, 0xb7, 0x18, 0x7e, 0xb2, 0x6b, 0xf9, 0x98, 0x6e, 0x13, 0x19, 0xc5, 0x0d, 0xe2, 0x35,
-	0xb0, 0xc7, 0x38, 0x0d, 0x45, 0x11, 0x4d, 0xe8, 0x60, 0xdf, 0x30, 0xe9, 0x75, 0x50, 0x10, 0xa0,
-	0x1c, 0x30, 0x36, 0x98, 0xa5, 0x81, 0x01, 0x35, 0x46, 0x6a, 0xcd, 0xd0, 0xa2, 0xe1, 0xd3, 0xa6,
-	0x20, 0xa6, 0x4d, 0x56, 0x58, 0x70, 0x1a, 0x01, 0x9a, 0x57, 0xa9, 0x70, 0x4b, 0x78, 0xa9, 0xfe,
-	0xa8, 0x80, 0x19, 0x46, 0xf6, 0xb0, 0x57, 0x23, 0x6d, 0x56, 0x6b, 0xf2, 0x2a, 0xcf, 0x0c, 0xab,
-	0xf2, 0x8a, 0x50, 0x33, 0x17, 0xaa, 0xe9, 0x17, 0x87, 0x89, 0xca, 0xff, 0xfd, 0x40, 0xf8, 0xab,
-	0x36, 0xab, 0x72, 0xd1, 0xdf, 0xd3, 0x60, 0x6d, 0xd4, 0x54, 0xc8, 0xbc, 0x3f, 0x05, 0x53, 0x56,
-	0x93, 0xb4, 0x3d, 0xb6, 0x24, 0x72, 0xb2, 0xc6, 0xcd, 0xfd, 0xab, 0xa3, 0xdd, 0xbd, 0x80, 0x55,
-	0x15, 0x8f, 0x75, 0xb3, 0x22, 0x60, 0xa0, 0x19, 0x01, 0x76, 0xb1, 0x8b, 0x41, 0x0e, 0xdf, 0x1a,
-	0xbb, 0x28, 0xb1, 0x8b, 0xea, 0x77, 0x60, 0xd6, 0x75, 0x9e, 0xb7, 0x1d, 0xe4, 0xb0, 0xc3, 0x5a,
-	0x23, 0xe8, 0x60, 0x14, 0xce, 0x82, 0xd2, 0xe3, 0x04, 0x5a, 0xca, 0xb8, 0xd1, 0xad, 0x80, 0x33,
-	0x80, 0xd0, 0xbc, 0x26, 0xef, 0xc2, 0x29, 0x81, 0xd4, 0x1d, 0x70, 0xf9, 0x5b, 0xe2, 0x78, 0x35,
-	0xbe, 0x13, 0x05, 0x23, 0x66, 0x7a, 0x39, 0xa7, 0x87, 0x0b, 0x93, 0x1e, 0x2d, 0x4c, 0xfa, 0x76,
-	0xb4, 0x30, 0x95, 0x6e, 0x89, 0xec, 0x5f, 0x0b, 0x55, 0x48, 0x51, 0xf8, 0xf2, 0x8d, 0xa6, 0x98,
-	0x97, 0xf8, 0x99, 0x33, 0xc3, 0x3f, 0xc2, 0xa1, 0xbc, 0x8e, 0xd0, 0x36, 0xe9, 0x4d, 0xd8, 0x66,
-	0xa4, 0xbf, 0x3b, 0x8b, 0x64, 0x3b, 0xad, 0x80, 0xe9, 0x68, 0xb2, 0xc8, 0x77, 0xae, 0x74, 0xe3,
-	0xa4, 0xa3, 0xa9, 0xd1, 0x20, 0x90, 0x44, 0xd8, 0x33, 0x84, 0x50, 0x4f, 0x1f, 0xa6, 0x86, 0xf5,
-	0x61, 0x2d, 0x2a, 0x78, 0x84, 0xa9, 0xe3, 0x63, 0xb4, 0x34, 0xbc, 0xaf, 0x6e, 0x0f, 0x2a, 0xf8,
-	0x48, 0x1c, 0x9a, 0x57, 0x82, 0x8b, 0xb2, 0x38, 0x9f, 0x51, 0x50, 0x14, 0x41, 0x1d, 0x51, 0x41,
-	0xf1, 0x94, 0x82, 0x22, 0x8f, 0xec, 0x4a, 0xc2, 0xc8, 0xca, 0xee, 0x18, 0x39, 0xc2, 0x3d, 0x6d,
-	0x95, 0x7a, 0x87, 0x6d, 0x95, 0x1e, 0x77, 0x5b, 0xf5, 0x8c, 0xdd, 0xcc, 0xb0, 0xb1, 0xbb, 0xfc,
-	0x2f, 0x00, 0xe9, 0x2a, 0xb5, 0x55, 0x1f, 0xa8, 0x83, 0x56, 0x06, 0xfd, 0xec, 0x3f, 0x2c, 0xfa,
-	0xc0, 0xcd, 0x3c, 0x57, 0xbc, 0x30, 0xab, 0xcc, 0xcc, 0x01, 0xb8, 0x3e, 0x70, 0x83, 0xbf, 0x37,
-	0x14, 0xaa, 0xcb, 0x9c, 0x7b, 0x90, 0x80, 0x39, 0x4e, 0xb3, 0xdc, 0x94, 0x2f, 0xa2, 0x39, 0x62,
-	0xbe, 0x90, 0xe6, 0x33, 0x3b, 0xed, 0x4f, 0x0a, 0xb8, 0x33, 0x7c, 0x63, 0x5f, 0x4d, 0xe0, 0x54,
-	0x9f, 0x64, 0x6e, 0x6d, 0x54, 0x49, 0x69, 0xe1, 0x0b, 0x05, 0xcc, 0xc7, 0x6f, 0xd6, 0x4b, 0x31,
-	0xf8, 0xb1, 0x12, 0xb9, 0xd5, 0xa4, 0x12, 0xd2, 0x92, 0x5f, 0x15, 0xb0, 0x98, 0x68, 0xc3, 0xdd,
-	0x88, 0x51, 0x95, 0x04, 0x24, 0xf7, 0xe5, 0x18, 0x40, 0xa4, 0x0b, 0xdf, 0x83, 0xb9, 0xc1, 0x7b,
-	0xe2, 0x62, 0x8c, 0x96, 0x81, 0xdc, 0xb9, 0x4f, 0x93, 0x70, 0x4b, 0xe5, 0x7f, 0x2b, 0xe0, 0xe1,
-	0x68, 0x4b, 0xde, 0x66, 0xac, 0xbe, 0x11, 0xd0, 0x72, 0xdb, 0xe3, 0x44, 0xeb, 0xab, 0x8e, 0x44,
-	0x4f, 0x6d, 0x5c, 0x75, 0x24, 0x01, 0x89, 0xad, 0x8e, 0x51, 0x9e, 0xa6, 0xd2, 0xd6, 0xab, 0xa3,
-	0xbc, 0xf2, 0xfa, 0x28, 0xaf, 0xfc, 0x73, 0x94, 0x57, 0x5e, 0x1e, 0xe7, 0x27, 0x5e, 0x1f, 0xe7,
-	0x27, 0xfe, 0x3c, 0xce, 0x4f, 0x3c, 0x7d, 0xd4, 0xf3, 0x0c, 0x08, 0x85, 0xf7, 0x5d, 0xab, 0x4e,
-	0xa3, 0x83, 0xb1, 0x5f, 0x7c, 0x68, 0x1c, 0xf4, 0xfd, 0xc6, 0xc4, 0x9f, 0x86, 0xfa, 0x64, 0xb0,
-	0xbe, 0x3c, 0xf8, 0x2f, 0x00, 0x00, 0xff, 0xff, 0x2f, 0x8b, 0x8c, 0x15, 0x86, 0x12, 0x00, 0x00,
+	// 1173 bytes of a gzipped FileDescriptorProto
+	0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xd4, 0x58, 0x41, 0x4f, 0x1b, 0x47,
+	0x14, 0x66, 0x6d, 0x17, 0x92, 0xa1, 0x90, 0xb0, 0x0d, 0x89, 0x71, 0x89, 0xd7, 0x99, 0x46, 0x11,
+	0x55, 0xc8, 0x2e, 0x26, 0x4d, 0x40, 0x3d, 0x81, 0xb1, 0x5a, 0x39, 0xc5, 0x2a, 0xda, 0x80, 0x2a,
+	0x45, 0xaa, 0x56, 0x6b, 0xcf, 0x64, 0xd9, 0xb2, 0xde, 0x71, 0x76, 0xc6, 0x14, 0xd4, 0x1f, 0x90,
+	0x6b, 0xfe, 0x41, 0xef, 0x3d, 0xf4, 0x37, 0xf4, 0xd6, 0xa8, 0xa7, 0xdc, 0x5a, 0xb5, 0x92, 0x53,
+	0xc1, 0x3f, 0xe0, 0xd8, 0x53, 0x35, 0xbb, 0xb3, 0xeb, 0x35, 0x78, 0x31, 0xeb, 0x90, 0x43, 0x4e,
+	0xec, 0xcc, 0xbc, 0xf7, 0x7d, 0xef, 0xbd, 0x79, 0xef, 0xcd, 0xc3, 0xe0, 0x53, 0x42, 0x5b, 0x84,
+	0xda, 0x54, 0xa3, 0x9d, 0x36, 0xf6, 0x9e, 0x3b, 0x1d, 0x1b, 0x69, 0xec, 0x40, 0x6d, 0x7b, 0x84,
+	0x11, 0x59, 0x16, 0x87, 0x6a, 0xef, 0xb0, 0x70, 0xc3, 0x22, 0x16, 0xf1, 0x8f, 0x35, 0xfe, 0x15,
+	0x48, 0x16, 0x8a, 0x16, 0x21, 0x96, 0x83, 0x35, 0x7f, 0xd5, 0xe8, 0x3c, 0xd7, 0x50, 0xc7, 0x33,
+	0x99, 0x4d, 0xdc, 0xf0, 0xbc, 0xe9, 0x43, 0x69, 0x0d, 0x93, 0x62, 0x6d, 0xbf, 0xdc, 0xc0, 0xcc,
+	0x2c, 0x6b, 0x4d, 0x62, 0x87, 0xe7, 0xca, 0x69, 0x7d, 0x66, 0xb7, 0x30, 0x65, 0x66, 0xab, 0x2d,
+	0x04, 0x3e, 0x1b, 0x60, 0x67, 0xef, 0x33, 0x10, 0x82, 0xfb, 0x60, 0xb6, 0x4e, 0xad, 0xa7, 0xd1,
+	0x76, 0x15, 0x3b, 0xd8, 0x32, 0x19, 0x96, 0x3f, 0x07, 0xe3, 0x14, 0xbb, 0x08, 0x7b, 0x79, 0xa9,
+	0x24, 0x2d, 0x5c, 0xad, 0xcc, 0x9c, 0x74, 0x95, 0xa9, 0x43, 0xb3, 0xe5, 0x7c, 0x09, 0x83, 0x7d,
+	0xa8, 0x0b, 0x01, 0xf9, 0x16, 0x98, 0x70, 0x48, 0x73, 0xcf, 0xb0, 0x51, 0x3e, 0x53, 0x92, 0x16,
+	0x72, 0xfa, 0x38, 0x5f, 0xd6, 0x90, 0x3c, 0x07, 0xae, 0xec, 0x9b, 0x8e, 0x61, 0x22, 0xe4, 0xe5,
+	0xb3, 0x1c, 0x45, 0x9f, 0xd8, 0x37, 0x9d, 0x75, 0x84, 0x3c, 0xa8, 0x80, 0xdb, 0x03, 0x79, 0x75,
+	0x4c, 0xdb, 0xc4, 0xa5, 0x18, 0x7e, 0x0f, 0x6e, 0xf5, 0x09, 0xec, 0xb8, 0xe8, 0x12, 0x4d, 0x83,
+	0x77, 0x80, 0x92, 0x00, 0x7f, 0x8e, 0x05, 0x0d, 0xe2, 0xa2, 0x4d, 0xd2, 0xdc, 0x7b, 0x4f, 0x16,
+	0x84, 0xf0, 0x91, 0x05, 0xbf, 0x4a, 0xe0, 0x6e, 0x82, 0x95, 0xeb, 0xee, 0x25, 0xdb, 0x23, 0x57,
+	0x40, 0x8e, 0x67, 0x97, 0x7f, 0x51, 0x93, 0xcb, 0x73, 0x6a, 0x90, 0x7e, 0x2a, 0x4f, 0x3f, 0x55,
+	0xa4, 0x9f, 0xba, 0x41, 0x6c, 0xb7, 0xf2, 0xc9, 0xeb, 0xae, 0x32, 0x76, 0xd2, 0x55, 0x26, 0x03,
+	0x02, 0xae, 0x04, 0x75, 0x5f, 0x17, 0x7e, 0x0d, 0x16, 0x2f, 0x62, 0x6f, 0xe8, 0x60, 0xdc, 0x18,
+	0xa9, 0x2f, 0x38, 0xbf, 0x4b, 0x60, 0xbe, 0x4e, 0x2d, 0x2e, 0xbc, 0xee, 0xa2, 0x77, 0x4b, 0x4f,
+	0x13, 0x7c, 0xc4, 0x8d, 0xa3, 0xf9, 0x4c, 0x29, 0x7b, 0xbe, 0x67, 0x4b, 0xdc, 0xb3, 0x5f, 0xde,
+	0x2a, 0x0b, 0x96, 0xcd, 0x76, 0x3b, 0x0d, 0xb5, 0x49, 0x5a, 0x9a, 0xa8, 0xc2, 0xe0, 0xcf, 0x03,
+	0x8a, 0xf6, 0x34, 0x76, 0xd8, 0xc6, 0xd4, 0x57, 0xa0, 0x7a, 0x80, 0x7c, 0x5e, 0xa2, 0x3f, 0xf6,
+	0xaf, 0x30, 0xd1, 0x91, 0x28, 0x14, 0xd3, 0x20, 0x53, 0xab, 0x8a, 0x28, 0x64, 0x6a, 0x55, 0xf8,
+	0x32, 0x03, 0xb4, 0x3a, 0xb5, 0x36, 0x3c, 0x6c, 0x32, 0xfc, 0x55, 0xc7, 0x71, 0x74, 0xd3, 0xb5,
+	0xf0, 0x16, 0xa1, 0x36, 0xef, 0x11, 0x1f, 0x76, 0x50, 0xe4, 0xfb, 0x60, 0xa2, 0x4d, 0x88, 0xc3,
+	0xef, 0x3d, 0xc7, 0x3d, 0xae, 0xc8, 0x27, 0x5d, 0x65, 0x3a, 0xb0, 0x54, 0x1c, 0x40, 0x7d, 0x9c,
+	0x7f, 0xd5, 0x10, 0x7c, 0x01, 0x56, 0x52, 0x06, 0x22, 0x0a, 0xea, 0x4d, 0x10, 0x24, 0x54, 0xb5,
+	0x2f, 0xbd, 0xaa, 0x72, 0x11, 0x80, 0xb6, 0x00, 0xa8, 0x55, 0x45, 0x1d, 0xc4, 0x76, 0xa0, 0x07,
+	0xf2, 0x75, 0x6a, 0xed, 0xb8, 0x5b, 0x84, 0x38, 0xdf, 0xed, 0xda, 0x0c, 0x3b, 0x36, 0x65, 0x18,
+	0xf1, 0x65, 0x9a, 0x20, 0xc7, 0xdc, 0xcc, 0x0c, 0x75, 0xf3, 0x09, 0x28, 0x25, 0x71, 0x46, 0xfe,
+	0xdc, 0x03, 0xd7, 0xf0, 0x81, 0xcd, 0x30, 0x32, 0x44, 0xd9, 0xd0, 0xbc, 0x54, 0xca, 0x2e, 0xe4,
+	0xf4, 0xa9, 0x60, 0x7b, 0xd3, 0xaf, 0x1e, 0x0a, 0x8f, 0x32, 0x60, 0xd5, 0x07, 0x73, 0x82, 0xbc,
+	0xab, 0xdb, 0x96, 0x67, 0x32, 0xfc, 0x74, 0xd7, 0xf4, 0x30, 0xdd, 0x26, 0x51, 0x14, 0x37, 0x88,
+	0xdb, 0xc4, 0x2e, 0xe3, 0x67, 0x28, 0x8c, 0x68, 0x4a, 0x07, 0xfb, 0x9a, 0x49, 0xdc, 0x41, 0x71,
+	0x00, 0xa3, 0x06, 0x63, 0x81, 0x19, 0xea, 0x1b, 0x60, 0x30, 0x62, 0xb4, 0x02, 0x8b, 0x86, 0x77,
+	0x9b, 0x92, 0xe8, 0x36, 0x79, 0x61, 0xc1, 0x69, 0x04, 0xa8, 0x5f, 0xa3, 0xc2, 0x2d, 0xe1, 0xa5,
+	0x8c, 0xc1, 0x34, 0x23, 0x7b, 0xd8, 0x35, 0x48, 0x87, 0x19, 0x2d, 0x9e, 0xe4, 0xb9, 0x61, 0x49,
+	0x7e, 0x57, 0xb0, 0xcc, 0x07, 0x2c, 0x7d, 0xea, 0x86, 0xd9, 0x22, 0x1d, 0x97, 0x51, 0xa8, 0x7f,
+	0xec, 0xef, 0x7f, 0xdb, 0x61, 0x75, 0xdb, 0xa5, 0xf0, 0x8f, 0x2c, 0x58, 0x1b, 0x35, 0xc8, 0xd1,
+	0x8d, 0x3e, 0x03, 0x13, 0x01, 0xfc, 0x92, 0x88, 0xf6, 0x1a, 0xb7, 0xe4, 0xef, 0xae, 0x72, 0xef,
+	0x02, 0xe5, 0x56, 0x73, 0x59, 0x2f, 0xde, 0x02, 0x06, 0xea, 0x21, 0x60, 0x0f, 0xbb, 0xec, 0xdf,
+	0xce, 0x3b, 0x63, 0x97, 0x23, 0xec, 0xb2, 0xfc, 0x23, 0x98, 0x71, 0xec, 0x17, 0x1d, 0x1b, 0xd9,
+	0xec, 0xd0, 0x68, 0xfa, 0xb5, 0x89, 0x82, 0x2a, 0xaf, 0x3c, 0x49, 0xc1, 0x52, 0xc5, 0xcd, 0xde,
+	0xdd, 0x9e, 0x01, 0x84, 0xfa, 0xf5, 0x68, 0x2f, 0xa8, 0x7f, 0x24, 0xef, 0x80, 0xab, 0x3f, 0x10,
+	0xdb, 0x35, 0xf8, 0xb4, 0xe3, 0x37, 0x8f, 0xc9, 0xe5, 0x82, 0x1a, 0x8c, 0x42, 0x6a, 0x38, 0x0a,
+	0xa9, 0xdb, 0xe1, 0x28, 0x54, 0x99, 0x17, 0x17, 0x7b, 0x3d, 0xa0, 0x88, 0x54, 0xe1, 0xab, 0xb7,
+	0x8a, 0xa4, 0x5f, 0xe1, 0x6b, 0x2e, 0x0c, 0xff, 0x0c, 0xda, 0xed, 0x3a, 0x42, 0xdb, 0x24, 0x7e,
+	0x61, 0x9b, 0x21, 0x7f, 0xaf, 0xcb, 0x44, 0x85, 0xb2, 0x02, 0x26, 0xc3, 0x9e, 0x11, 0xbd, 0x60,
+	0x95, 0x9b, 0x27, 0x5d, 0x45, 0x0e, 0x4b, 0x3c, 0x3a, 0x84, 0xb1, 0xf6, 0x82, 0x62, 0x15, 0x96,
+	0x19, 0x56, 0x61, 0x46, 0x98, 0xcb, 0x08, 0x53, 0xdb, 0xc3, 0x68, 0x69, 0x78, 0xc5, 0xdc, 0x16,
+	0x2e, 0xcf, 0xc6, 0x73, 0x39, 0x54, 0x87, 0xfa, 0x94, 0xbf, 0x51, 0x15, 0xeb, 0x33, 0x04, 0x65,
+	0x11, 0xd4, 0x11, 0x09, 0xca, 0xa7, 0x08, 0xca, 0x3c, 0xb2, 0x2b, 0x29, 0x23, 0x1b, 0x55, 0xc7,
+	0xc8, 0x11, 0x8e, 0x95, 0x55, 0xe6, 0x3d, 0x96, 0x55, 0xf6, 0xb2, 0xcb, 0x2a, 0xd6, 0x50, 0x73,
+	0xc3, 0x1a, 0xea, 0xf2, 0x7f, 0x00, 0x64, 0xeb, 0xd4, 0x92, 0x3d, 0x20, 0x0f, 0x1a, 0x06, 0xd4,
+	0xb3, 0xff, 0x8a, 0xa8, 0x03, 0x67, 0xee, 0x42, 0xf9, 0xc2, 0xa2, 0xd1, 0xcd, 0x1c, 0x80, 0x1b,
+	0x03, 0x67, 0xf3, 0xfb, 0x43, 0xa1, 0x7a, 0xc2, 0x85, 0x87, 0x29, 0x84, 0x93, 0x98, 0xa3, 0x19,
+	0xf8, 0x22, 0xcc, 0xa1, 0xf0, 0x85, 0x98, 0xcf, 0x4c, 0xab, 0x3f, 0x4b, 0xe0, 0xce, 0xf0, 0x59,
+	0x7c, 0x35, 0x85, 0x53, 0x7d, 0x9a, 0x85, 0xb5, 0x51, 0x35, 0x23, 0x0b, 0x5f, 0x4a, 0x60, 0x2e,
+	0x79, 0x66, 0x5e, 0x4a, 0xc0, 0x4f, 0xd4, 0x28, 0xac, 0xa6, 0xd5, 0x88, 0x2c, 0xf9, 0x4d, 0x02,
+	0x8b, 0xa9, 0x66, 0xd7, 0x8d, 0x04, 0xaa, 0x34, 0x20, 0x85, 0x6f, 0x2e, 0x01, 0x24, 0x72, 0xe1,
+	0x27, 0x30, 0x3b, 0x78, 0x02, 0x5c, 0x4c, 0x60, 0x19, 0x28, 0x5d, 0xf8, 0x22, 0x8d, 0x74, 0x44,
+	0xfe, 0x8f, 0x04, 0x1e, 0x8d, 0x36, 0xbe, 0x6d, 0x26, 0xf2, 0x8d, 0x80, 0x56, 0xd8, 0xbe, 0x4c,
+	0xb4, 0xbe, 0xec, 0x48, 0xf5, 0xd4, 0x26, 0x65, 0x47, 0x1a, 0x90, 0xc4, 0xec, 0x18, 0xe5, 0x69,
+	0xaa, 0x6c, 0xbd, 0x3e, 0x2a, 0x4a, 0x6f, 0x8e, 0x8a, 0xd2, 0xbf, 0x47, 0x45, 0xe9, 0xd5, 0x71,
+	0x71, 0xec, 0xcd, 0x71, 0x71, 0xec, 0xaf, 0xe3, 0xe2, 0xd8, 0xb3, 0xc7, 0xb1, 0x67, 0x40, 0x10,
+	0x3e, 0x70, 0xcc, 0x06, 0x0d, 0x17, 0xda, 0x7e, 0xf9, 0x91, 0x76, 0xd0, 0xf7, 0xeb, 0x11, 0x7f,
+	0x1a, 0x1a, 0xe3, 0xfe, 0xf8, 0xf2, 0xf0, 0xff, 0x00, 0x00, 0x00, 0xff, 0xff, 0x1f, 0x23, 0xf9,
+	0xff, 0x60, 0x12, 0x00, 0x00,
 }
 
 // Reference imports to suppress errors if they are not otherwise used.


Test patch:
diff --git a/tests/cl-genesis-positions/go.mod b/tests/cl-genesis-positions/go.mod
index 0a68fbc9d..efb9515b2 100644
--- a/tests/cl-genesis-positions/go.mod
+++ b/tests/cl-genesis-positions/go.mod
@@ -6,7 +6,7 @@ require (
 	github.com/cosmos/cosmos-sdk v0.47.2
 	github.com/ignite/cli v0.23.0
 	github.com/osmosis-labs/osmosis/osmomath v0.0.3-dev.0.20230503232557-ba905586c111
-	github.com/osmosis-labs/osmosis/v15 v15.0.0-20230513050746-13c81d83ef0d
+	github.com/osmosis-labs/osmosis/v15 v15.0.0-20230504143153-c7d6a52cd9f5
 	github.com/tendermint/tendermint v0.34.26
 )
 
@@ -101,7 +101,7 @@ require (
 	github.com/petermattis/goid v0.0.0-20180202154549-b0b1615b78e5 // indirect
 	github.com/pkg/errors v0.9.1 // indirect
 	github.com/pmezard/go-difflib v1.0.0 // indirect
-	github.com/prometheus/client_golang v1.15.1 // indirect
+	github.com/prometheus/client_golang v1.15.0 // indirect
 	github.com/prometheus/client_model v0.3.0 // indirect
 	github.com/prometheus/common v0.42.0 // indirect
 	github.com/prometheus/procfs v0.9.0 // indirect
diff --git a/tests/cl-genesis-positions/go.sum b/tests/cl-genesis-positions/go.sum
index 4d8ef90bc..2f77fd7ff 100644
--- a/tests/cl-genesis-positions/go.sum
+++ b/tests/cl-genesis-positions/go.sum
@@ -695,10 +695,12 @@ github.com/osmosis-labs/cosmos-sdk v0.45.1-0.20230326212251-7a2cf2993434 h1:RetE
 github.com/osmosis-labs/cosmos-sdk v0.45.1-0.20230326212251-7a2cf2993434/go.mod h1:ss3tUfPTwaa6NsoPZrCR7xOqLqCK0LwoNbc2Q8Zs5/Y=
 github.com/osmosis-labs/osmosis/osmomath v0.0.3-dev.0.20230503232557-ba905586c111 h1:1ahWbf9iF9sxDOjxrHWFaBGLE0nWFdpiX1pqObUaJO8=
 github.com/osmosis-labs/osmosis/osmomath v0.0.3-dev.0.20230503232557-ba905586c111/go.mod h1:a7lhiXRpn8QJ21OhFpaEnUNErTSIafaYpp02q6uI/Dk=
+github.com/osmosis-labs/osmosis/osmoutils v0.0.0-20230504001814-1dbcc2079de1 h1:1yzJYsP1bWOX/8/aGA8Mk/UFiU9z/h6LRAr2OezyYQ8=
+github.com/osmosis-labs/osmosis/osmoutils v0.0.0-20230504001814-1dbcc2079de1/go.mod h1:hk/o9/kmTSZmZqwXcSrPuwj/gpRMCqbE/d3vj6teL2A=
 github.com/osmosis-labs/osmosis/osmoutils v0.0.0-20230510161551-8bf252f26bae h1:I1Cy+GpTPWbVi0lBw9+bS1w42YfQjvXNK9bW4YbHhcs=
 github.com/osmosis-labs/osmosis/osmoutils v0.0.0-20230510161551-8bf252f26bae/go.mod h1:hk/o9/kmTSZmZqwXcSrPuwj/gpRMCqbE/d3vj6teL2A=
-github.com/osmosis-labs/osmosis/v15 v15.0.0-20230513050746-13c81d83ef0d h1:8lJNaOABRchMwMO+DoHEGrlrBXlhDloms1GKs/ti8HA=
-github.com/osmosis-labs/osmosis/v15 v15.0.0-20230513050746-13c81d83ef0d/go.mod h1:mdvXaHvcLi1Loo2sUF1FPV3RynReBpexO3g3ktEWQA4=
+github.com/osmosis-labs/osmosis/v15 v15.0.0-20230504143153-c7d6a52cd9f5 h1:M4fG/zxok1+9y5SWas1sBzDZWfSbGs7vezE1NF7niCk=
+github.com/osmosis-labs/osmosis/v15 v15.0.0-20230504143153-c7d6a52cd9f5/go.mod h1:NEoCQ+jkE0o6CUorEUhRdwdbvXYl5nt4oZeevaEz29o=
 github.com/osmosis-labs/osmosis/x/epochs v0.0.0-20230328024000-175ec88e4304 h1:RIrWLzIiZN5Xd2JOfSOtGZaf6V3qEQYg6EaDTAkMnCo=
 github.com/osmosis-labs/osmosis/x/epochs v0.0.0-20230328024000-175ec88e4304/go.mod h1:yPWoJTj5RKrXKUChAicp+G/4Ni/uVEpp27mi/FF/L9c=
 github.com/osmosis-labs/osmosis/x/ibc-hooks v0.0.0-20230331072320-5d6f6cfa2627 h1:A0SwZgp4bmJFbivYJc8mmVhMjrr3EdUZluBYFke11+w=
@@ -742,8 +744,8 @@ github.com/prometheus/client_golang v1.0.0/go.mod h1:db9x61etRT2tGnBNRi70OPL5Fsn
 github.com/prometheus/client_golang v1.3.0/go.mod h1:hJaj2vgQTGQmVCsAACORcieXFeDPbaTKGT+JTgUa3og=
 github.com/prometheus/client_golang v1.4.0/go.mod h1:e9GMxYsXl05ICDXkRhurwBS4Q3OK1iX/F2sw+iXX5zU=
 github.com/prometheus/client_golang v1.7.1/go.mod h1:PY5Wy2awLA44sXw4AOSfFBetzPP4j5+D6mVACh+pe2M=
-github.com/prometheus/client_golang v1.15.1 h1:8tXpTmJbyH5lydzFPoxSIJ0J46jdh3tylbvM1xCv0LI=
-github.com/prometheus/client_golang v1.15.1/go.mod h1:e9yaBhRPU2pPNsZwE+JdQl0KEt1N9XgF6zxWmaC0xOk=
+github.com/prometheus/client_golang v1.15.0 h1:5fCgGYogn0hFdhyhLbw7hEsWxufKtY9klyvdNfFlFhM=
+github.com/prometheus/client_golang v1.15.0/go.mod h1:e9yaBhRPU2pPNsZwE+JdQl0KEt1N9XgF6zxWmaC0xOk=
 github.com/prometheus/client_model v0.0.0-20180712105110-5c3871d89910/go.mod h1:MbSGuTsp3dbXC40dX6PRTWyKYBIrTGTE9sqQNg2J8bo=
 github.com/prometheus/client_model v0.0.0-20190115171406-56726106282f/go.mod h1:MbSGuTsp3dbXC40dX6PRTWyKYBIrTGTE9sqQNg2J8bo=
 github.com/prometheus/client_model v0.0.0-20190129233127-fd36f4220a90/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA=
diff --git a/tests/cl-go-client/go.mod b/tests/cl-go-client/go.mod
index 9a94e464c..5d209c66e 100644
--- a/tests/cl-go-client/go.mod
+++ b/tests/cl-go-client/go.mod
@@ -5,7 +5,7 @@ go 1.20
 require (
 	github.com/cosmos/cosmos-sdk v0.47.2
 	github.com/ignite/cli v0.23.0
-	github.com/osmosis-labs/osmosis/v15 v15.0.0-20230502194055-13c81d83ef0d
+	github.com/osmosis-labs/osmosis/v15 v15.0.0-20230502194055-e465f0b40c14
 
 )
 
diff --git a/tests/cl-go-client/go.sum b/tests/cl-go-client/go.sum
index 12dcffdbb..f6d58cd00 100644
--- a/tests/cl-go-client/go.sum
+++ b/tests/cl-go-client/go.sum
@@ -688,6 +688,7 @@ github.com/osmosis-labs/cosmos-sdk v0.45.1-0.20230326212251-7a2cf2993434 h1:RetE
 github.com/osmosis-labs/cosmos-sdk v0.45.1-0.20230326212251-7a2cf2993434/go.mod h1:ss3tUfPTwaa6NsoPZrCR7xOqLqCK0LwoNbc2Q8Zs5/Y=
 github.com/osmosis-labs/osmosis/osmomath v0.0.3-dev.0.20230503232557-ba905586c111 h1:1ahWbf9iF9sxDOjxrHWFaBGLE0nWFdpiX1pqObUaJO8=
 github.com/osmosis-labs/osmosis/osmomath v0.0.3-dev.0.20230503232557-ba905586c111/go.mod h1:a7lhiXRpn8QJ21OhFpaEnUNErTSIafaYpp02q6uI/Dk=
+github.com/osmosis-labs/osmosis/osmoutils v0.0.0-20230504190933-b174397f0bc5 h1:fBzTtgZHxvZkpwlg6YtAsNaexEHYaFZDXsYfPQWu9GE=
 github.com/osmosis-labs/osmosis/osmoutils v0.0.0-20230510161551-8bf252f26bae h1:I1Cy+GpTPWbVi0lBw9+bS1w42YfQjvXNK9bW4YbHhcs=
 github.com/osmosis-labs/osmosis/osmoutils v0.0.0-20230510161551-8bf252f26bae/go.mod h1:hk/o9/kmTSZmZqwXcSrPuwj/gpRMCqbE/d3vj6teL2A=
 github.com/osmosis-labs/osmosis/x/epochs v0.0.0-20230328024000-175ec88e4304 h1:RIrWLzIiZN5Xd2JOfSOtGZaf6V3qEQYg6EaDTAkMnCo=
@@ -730,6 +731,8 @@ github.com/prometheus/client_golang v1.0.0/go.mod h1:db9x61etRT2tGnBNRi70OPL5Fsn
 github.com/prometheus/client_golang v1.3.0/go.mod h1:hJaj2vgQTGQmVCsAACORcieXFeDPbaTKGT+JTgUa3og=
 github.com/prometheus/client_golang v1.4.0/go.mod h1:e9GMxYsXl05ICDXkRhurwBS4Q3OK1iX/F2sw+iXX5zU=
 github.com/prometheus/client_golang v1.7.1/go.mod h1:PY5Wy2awLA44sXw4AOSfFBetzPP4j5+D6mVACh+pe2M=
+github.com/prometheus/client_golang v1.15.0 h1:5fCgGYogn0hFdhyhLbw7hEsWxufKtY9klyvdNfFlFhM=
+github.com/prometheus/client_golang v1.15.0/go.mod h1:e9yaBhRPU2pPNsZwE+JdQl0KEt1N9XgF6zxWmaC0xOk=
 github.com/prometheus/client_golang v1.15.1 h1:8tXpTmJbyH5lydzFPoxSIJ0J46jdh3tylbvM1xCv0LI=
 github.com/prometheus/client_golang v1.15.1/go.mod h1:e9yaBhRPU2pPNsZwE+JdQl0KEt1N9XgF6zxWmaC0xOk=
 github.com/prometheus/client_model v0.0.0-20180712105110-5c3871d89910/go.mod h1:MbSGuTsp3dbXC40dX6PRTWyKYBIrTGTE9sqQNg2J8bo=
diff --git a/tests/e2e/e2e_test.go b/tests/e2e/e2e_test.go
index 8c9448bae..63f60d3ee 100644
--- a/tests/e2e/e2e_test.go
+++ b/tests/e2e/e2e_test.go
@@ -371,9 +371,9 @@ func (s *IntegrationTestSuite) TestConcentratedLiquidity() {
 	nextInitTick := sdk.NewInt(40000) // address1 position1's upper tick
 
 	// Calculate sqrtPrice after and at the next initialized tick (upperTick of address1 position1 - 40000)
-	sqrtPriceAfterNextInitializedTick, err := cl.TickToSqrtPrice(nextInitTick.Add(tickOffset))
+	_, sqrtPriceAfterNextInitializedTick, err := cl.TickToSqrtPrice(nextInitTick.Add(tickOffset))
 	s.Require().NoError(err)
-	sqrtPriceAtNextInitializedTick, err := cl.TickToSqrtPrice(nextInitTick)
+	_, sqrtPriceAtNextInitializedTick, err := cl.TickToSqrtPrice(nextInitTick)
 	s.Require().NoError(err)
 
 	// Calculate Δ(sqrtPrice):
@@ -513,9 +513,9 @@ func (s *IntegrationTestSuite) TestConcentratedLiquidity() {
 	// Using: CalcAmount0Delta = liquidity * ((sqrtPriceB - sqrtPriceA) / (sqrtPriceB * sqrtPriceA))
 
 	// Calculate sqrtPrice after and at the next initialized tick (which is upperTick of address1 position1 - 40000)
-	sqrtPricebBelowNextInitializedTick, err := cl.TickToSqrtPrice(nextInitTick.Sub(tickOffset))
+	_, sqrtPricebBelowNextInitializedTick, err := cl.TickToSqrtPrice(nextInitTick.Sub(tickOffset))
 	s.Require().NoError(err)
-	sqrtPriceAtNextInitializedTick, err = cl.TickToSqrtPrice(nextInitTick)
+	_, sqrtPriceAtNextInitializedTick, err = cl.TickToSqrtPrice(nextInitTick)
 	s.Require().NoError(err)
 
 	// Calculate numerators
diff --git a/x/concentrated-liquidity/export_test.go b/x/concentrated-liquidity/export_test.go
index 560796484..35ede63a2 100644
--- a/x/concentrated-liquidity/export_test.go
+++ b/x/concentrated-liquidity/export_test.go
@@ -143,6 +143,10 @@ 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) {
+	return roundTickToCanonicalPriceTick(lowerTick, upperTick, priceTickLower, priceTickUpper, tickSpacing)
+}
+
 // fees methods
 func (k Keeper) CreateFeeAccumulator(ctx sdk.Context, poolId uint64) error {
 	return k.createFeeAccumulator(ctx, poolId)
@@ -176,7 +180,7 @@ func PreparePositionAccumulator(feeAccumulator accum.AccumulatorObject, position
 	return preparePositionAccumulator(feeAccumulator, positionKey, feeGrowthOutside)
 }
 
-func (k Keeper) CreatePosition(ctx sdk.Context, poolId uint64, owner sdk.AccAddress, tokensProvided sdk.Coins, amount0Min, amount1Min sdk.Int, lowerTick, upperTick int64) (uint64, sdk.Int, sdk.Int, sdk.Dec, time.Time, error) {
+func (k Keeper) CreatePosition(ctx sdk.Context, poolId uint64, owner sdk.AccAddress, tokensProvided sdk.Coins, amount0Min, amount1Min sdk.Int, lowerTick, upperTick int64) (positionId uint64, actualAmount0 sdk.Int, actualAmount1 sdk.Int, liquidityDelta sdk.Dec, joinTime time.Time, lowerTickResult int64, upperTickResult int64, err error) {
 	return k.createPosition(ctx, poolId, owner, tokensProvided, amount0Min, amount1Min, lowerTick, upperTick)
 }
 
diff --git a/x/concentrated-liquidity/fees_test.go b/x/concentrated-liquidity/fees_test.go
index 0ee5d92b9..0cb723192 100644
--- a/x/concentrated-liquidity/fees_test.go
+++ b/x/concentrated-liquidity/fees_test.go
@@ -1503,7 +1503,7 @@ func (s *KeeperTestSuite) TestFunctional_Fees_LP() {
 	s.Require().Error(err)
 
 	// Create position in the default range 1.
-	positionIdOne, _, _, liquidity, _, err := concentratedLiquidityKeeper.CreatePosition(ctx, pool.GetId(), owner, DefaultCoins, sdk.ZeroInt(), sdk.ZeroInt(), DefaultLowerTick, DefaultUpperTick)
+	positionIdOne, _, _, liquidity, _, _, _, err := concentratedLiquidityKeeper.CreatePosition(ctx, pool.GetId(), owner, DefaultCoins, sdk.ZeroInt(), sdk.ZeroInt(), DefaultLowerTick, DefaultUpperTick)
 	s.Require().NoError(err)
 
 	// Swap once.
@@ -1527,7 +1527,7 @@ func (s *KeeperTestSuite) TestFunctional_Fees_LP() {
 	s.validatePositionFeeGrowth(pool.GetId(), positionIdOne, cl.EmptyCoins)
 
 	// Create position in the default range 2.
-	positionIdTwo, _, _, fullLiquidity, _, err := concentratedLiquidityKeeper.CreatePosition(ctx, pool.GetId(), owner, DefaultCoins, sdk.ZeroInt(), sdk.ZeroInt(), DefaultLowerTick, DefaultUpperTick)
+	positionIdTwo, _, _, fullLiquidity, _, _, _, err := concentratedLiquidityKeeper.CreatePosition(ctx, pool.GetId(), owner, DefaultCoins, sdk.ZeroInt(), sdk.ZeroInt(), DefaultLowerTick, DefaultUpperTick)
 	s.Require().NoError(err)
 
 	// Swap once in the other direction.
@@ -1555,7 +1555,7 @@ func (s *KeeperTestSuite) TestFunctional_Fees_LP() {
 	s.Require().Equal(expectesFeesCollected.String(), feesCollected.AmountOf(ETH).String())
 
 	// Create position in the default range 3.
-	positionIdThree, _, _, fullLiquidity, _, err := concentratedLiquidityKeeper.CreatePosition(ctx, pool.GetId(), owner, DefaultCoins, sdk.ZeroInt(), sdk.ZeroInt(), DefaultLowerTick, DefaultUpperTick)
+	positionIdThree, _, _, fullLiquidity, _, _, _, err := concentratedLiquidityKeeper.CreatePosition(ctx, pool.GetId(), owner, DefaultCoins, sdk.ZeroInt(), sdk.ZeroInt(), DefaultLowerTick, DefaultUpperTick)
 	s.Require().NoError(err)
 
 	collectedThree, err := s.App.ConcentratedLiquidityKeeper.CollectFees(ctx, owner, positionIdThree)
diff --git a/x/concentrated-liquidity/incentives_test.go b/x/concentrated-liquidity/incentives_test.go
index f39ef5acd..68e2ed667 100644
--- a/x/concentrated-liquidity/incentives_test.go
+++ b/x/concentrated-liquidity/incentives_test.go
@@ -940,7 +940,7 @@ func (s *KeeperTestSuite) TestUpdateUptimeAccumulatorsToNow() {
 			if !tc.isInvalidBalancerPool {
 				depositedCoins := sdk.NewCoins(sdk.NewCoin(clPool.GetToken0(), testQualifyingDepositsOne), sdk.NewCoin(clPool.GetToken1(), testQualifyingDepositsOne))
 				s.FundAcc(testAddressOne, depositedCoins)
-				_, _, _, qualifyingLiquidity, _, err = clKeeper.CreatePosition(s.Ctx, clPool.GetId(), testAddressOne, depositedCoins, sdk.ZeroInt(), sdk.ZeroInt(), clPool.GetCurrentTick().Int64()-100, clPool.GetCurrentTick().Int64()+100)
+				_, _, _, qualifyingLiquidity, _, _, _, err = clKeeper.CreatePosition(s.Ctx, clPool.GetId(), testAddressOne, depositedCoins, sdk.ZeroInt(), sdk.ZeroInt(), clPool.GetCurrentTick().Int64()-100, clPool.GetCurrentTick().Int64()+100)
 				s.Require().NoError(err)
 
 				// If a canonical balancer pool exists, we add its respective shares to the qualifying amount as well.
@@ -3589,7 +3589,7 @@ func (s *KeeperTestSuite) TestFunctional_ClaimIncentices_LiquidityChange_Varying
 	s.Require().NoError(err)
 
 	// Set up position
-	positionIdOne, _, _, _, _, err := s.App.ConcentratedLiquidityKeeper.CreatePosition(s.Ctx, defaultPoolId, defaultAddress, DefaultCoins, sdk.ZeroInt(), sdk.ZeroInt(), DefaultLowerTick, DefaultUpperTick)
+	positionIdOne, _, _, _, _, _, _, err := s.App.ConcentratedLiquidityKeeper.CreatePosition(s.Ctx, defaultPoolId, defaultAddress, DefaultCoins, sdk.ZeroInt(), sdk.ZeroInt(), DefaultLowerTick, DefaultUpperTick)
 	s.Require().NoError(err)
 
 	// Increase block time by the fully charged duration (first time)
@@ -3604,7 +3604,7 @@ func (s *KeeperTestSuite) TestFunctional_ClaimIncentices_LiquidityChange_Varying
 	s.Ctx = s.Ctx.WithBlockTime(s.Ctx.BlockTime().Add(testFullChargeDuration))
 
 	// Create another position
-	positionIdTwo, _, _, _, _, err := s.App.ConcentratedLiquidityKeeper.CreatePosition(s.Ctx, defaultPoolId, defaultAddress, DefaultCoins, sdk.ZeroInt(), sdk.ZeroInt(), DefaultLowerTick, DefaultUpperTick)
+	positionIdTwo, _, _, _, _, _, _, err := s.App.ConcentratedLiquidityKeeper.CreatePosition(s.Ctx, defaultPoolId, defaultAddress, DefaultCoins, sdk.ZeroInt(), sdk.ZeroInt(), DefaultLowerTick, DefaultUpperTick)
 	s.Require().NoError(err)
 
 	// Increase block time by the fully charged duration (third time)
diff --git a/x/concentrated-liquidity/keeper_test.go b/x/concentrated-liquidity/keeper_test.go
index 5c815c91a..0abfb7885 100644
--- a/x/concentrated-liquidity/keeper_test.go
+++ b/x/concentrated-liquidity/keeper_test.go
@@ -74,7 +74,7 @@ func (s *KeeperTestSuite) SetupDefaultPosition(poolId uint64) {
 
 func (s *KeeperTestSuite) SetupPosition(poolId uint64, owner sdk.AccAddress, providedCoins sdk.Coins, lowerTick, upperTick int64, joinTime time.Time) (sdk.Dec, uint64) {
 	s.FundAcc(owner, providedCoins)
-	positionId, _, _, _, _, err := s.App.ConcentratedLiquidityKeeper.CreatePosition(s.Ctx, poolId, owner, providedCoins, sdk.ZeroInt(), sdk.ZeroInt(), lowerTick, upperTick)
+	positionId, _, _, _, _, _, _, err := s.App.ConcentratedLiquidityKeeper.CreatePosition(s.Ctx, poolId, owner, providedCoins, sdk.ZeroInt(), sdk.ZeroInt(), lowerTick, upperTick)
 	s.Require().NoError(err)
 	liquidity, err := s.App.ConcentratedLiquidityKeeper.GetPositionLiquidity(s.Ctx, positionId)
 	s.Require().NoError(err)
@@ -136,13 +136,13 @@ func (s *KeeperTestSuite) validateTickUpdates(ctx sdk.Context, poolId uint64, ow
 	s.Require().NoError(err)
 	s.Require().Equal(expectedRemainingLiquidity.String(), lowerTickInfo.LiquidityGross.String())
 	s.Require().Equal(expectedRemainingLiquidity.String(), lowerTickInfo.LiquidityNet.String())
-	s.Require().Equal(lowerTickInfo.FeeGrowthOppositeDirectionOfLastTraversal.String(), expectedLowerFeeGrowthOppositeDirectionOfLastTraversal.String())
+	s.Require().Equal(expectedLowerFeeGrowthOppositeDirectionOfLastTraversal.String(), lowerTickInfo.FeeGrowthOppositeDirectionOfLastTraversal.String())
 
 	upperTickInfo, err := s.App.ConcentratedLiquidityKeeper.GetTickInfo(s.Ctx, poolId, upperTick)
 	s.Require().NoError(err)
 	s.Require().Equal(expectedRemainingLiquidity.String(), upperTickInfo.LiquidityGross.String())
 	s.Require().Equal(expectedRemainingLiquidity.Neg().String(), upperTickInfo.LiquidityNet.String())
-	s.Require().Equal(upperTickInfo.FeeGrowthOppositeDirectionOfLastTraversal.String(), expectedUpperFeeGrowthOppositeDirectionOfLastTraversal.String())
+	s.Require().Equal(expectedUpperFeeGrowthOppositeDirectionOfLastTraversal.String(), upperTickInfo.FeeGrowthOppositeDirectionOfLastTraversal.String())
 }
 
 func (s *KeeperTestSuite) initializeTick(ctx sdk.Context, currentTick int64, tickIndex int64, initialLiquidity sdk.Dec, feeGrowthOppositeDirectionOfTraversal sdk.DecCoins, uptimeTrackers []model.UptimeTracker, isLower bool) {
diff --git a/x/concentrated-liquidity/lp_test.go b/x/concentrated-liquidity/lp_test.go
index 373a7976e..d613081ad 100644
--- a/x/concentrated-liquidity/lp_test.go
+++ b/x/concentrated-liquidity/lp_test.go
@@ -18,7 +18,9 @@ type lpTest struct {
 	poolId                            uint64
 	currentTick                       sdk.Int
 	lowerTick                         int64
+	expectedLowerTick                 int64
 	upperTick                         int64
+	expectedUpperTick                 int64
 	joinTime                          time.Time
 	positionId                        uint64
 	underlyingLockId                  uint64
@@ -152,6 +154,25 @@ var (
 			amount0Expected: DefaultAmt0Expected.Add(roundingError),
 			amount1Expected: DefaultAmt1Expected,
 		},
+		"use ticks that are not the canonical tick for a given price, expect them to be rounded to the proper tick": {
+			lowerTick:         -161987600,
+			expectedLowerTick: -161000000,
+			upperTick:         -160009800,
+			expectedUpperTick: -160000000,
+			currentTick:       sdk.NewInt(DefaultUpperTick),
+
+			isNotFirstPositionWithSameAccount: true,
+			positionId:                        2,
+
+			liquidityAmount:               sdk.MustNewDecFromStr("15731321859400083838.506717486806808937").MulInt64(2),
+			preSetChargeFee:               oneEth,
+			expectedFeeGrowthOutsideLower: oneEthCoins,
+			expectedFeeGrowthOutsideUpper: oneEthCoins,
+
+			// Rounding up in favor of the pool.
+			amount0Expected: sdk.ZeroInt(),
+			amount1Expected: DefaultAmt1,
+		},
 	}
 )
 
@@ -287,7 +308,7 @@ func (s *KeeperTestSuite) TestCreatePosition() {
 			poolBalancePrePositionCreation := s.App.BankKeeper.GetAllBalances(s.Ctx, pool.GetAddress())
 
 			// System under test.
-			positionId, asset0, asset1, liquidityCreated, joinTime, err := clKeeper.CreatePosition(s.Ctx, tc.poolId, s.TestAccs[0], tc.tokensProvided, tc.amount0Minimum, tc.amount1Minimum, tc.lowerTick, tc.upperTick)
+			positionId, asset0, asset1, liquidityCreated, joinTime, newLowerTick, newUpperTick, err := clKeeper.CreatePosition(s.Ctx, tc.poolId, s.TestAccs[0], tc.tokensProvided, tc.amount0Minimum, tc.amount1Minimum, tc.lowerTick, tc.upperTick)
 
 			// Note user and pool account balances to compare after create position is called
 			userBalancePostPositionCreation := s.App.BankKeeper.GetAllBalances(s.Ctx, s.TestAccs[0])
@@ -323,6 +344,14 @@ func (s *KeeperTestSuite) TestCreatePosition() {
 			s.Require().Equal(tc.amount1Expected.String(), asset1.String())
 			s.Require().Equal(expectedLiquidityCreated.String(), liquidityCreated.String())
 			s.Require().Equal(s.Ctx.BlockTime(), joinTime)
+			if tc.expectedLowerTick != 0 {
+				s.Require().Equal(tc.expectedLowerTick, newLowerTick)
+				tc.lowerTick = newLowerTick
+			}
+			if tc.expectedUpperTick != 0 {
+				s.Require().Equal(tc.expectedUpperTick, newUpperTick)
+				tc.upperTick = newUpperTick
+			}
 
 			// Check account balances
 			s.Require().Equal(userBalancePrePositionCreation.Sub(sdk.NewCoins(sdk.NewCoin(ETH, asset0), (sdk.NewCoin(USDC, asset1)))).String(), userBalancePostPositionCreation.String())
@@ -500,7 +529,7 @@ func (s *KeeperTestSuite) TestWithdrawPosition() {
 				_, _, _, liquidityCreated, _, _, err = concentratedLiquidityKeeper.CreateFullRangePositionUnlocking(s.Ctx, pool.GetId(), owner, fundCoins, tc.timeElapsed-time.Hour)
 				s.Require().NoError(err)
 			} else {
-				_, _, _, liquidityCreated, _, err = concentratedLiquidityKeeper.CreatePosition(s.Ctx, pool.GetId(), owner, config.tokensProvided, sdk.ZeroInt(), sdk.ZeroInt(), DefaultLowerTick, DefaultUpperTick)
+				_, _, _, liquidityCreated, _, _, _, err = concentratedLiquidityKeeper.CreatePosition(s.Ctx, pool.GetId(), owner, config.tokensProvided, sdk.ZeroInt(), sdk.ZeroInt(), DefaultLowerTick, DefaultUpperTick)
 				s.Require().NoError(err)
 			}
 
@@ -642,7 +671,7 @@ func (s *KeeperTestSuite) TestWithdrawPosition() {
 			if expectedRemainingLiquidity.IsZero() {
 				// Add one USDC because we withdraw one less than originally funded due to truncation in favor of the pool.
 				s.FundAcc(owner, sdk.NewCoins(sdk.NewCoin(USDC, sdk.OneInt())))
-				_, _, _, _, _, err = concentratedLiquidityKeeper.CreatePosition(s.Ctx, pool.GetId(), owner, config.tokensProvided, sdk.ZeroInt(), sdk.ZeroInt(), DefaultLowerTick, DefaultUpperTick)
+				_, _, _, _, _, _, _, err = concentratedLiquidityKeeper.CreatePosition(s.Ctx, pool.GetId(), owner, config.tokensProvided, sdk.ZeroInt(), sdk.ZeroInt(), DefaultLowerTick, DefaultUpperTick)
 				s.Require().NoError(err)
 			}
 		})
@@ -944,14 +973,14 @@ func (s *KeeperTestSuite) TestAddToPosition() {
 				_, amount0Initial, amount1Initial, _, _, _, err = concentratedLiquidityKeeper.CreateFullRangePositionUnlocking(s.Ctx, pool.GetId(), owner, fundCoins, tc.timeElapsed-time.Hour)
 				s.Require().NoError(err)
 			} else {
-				_, amount0Initial, amount1Initial, _, _, err = concentratedLiquidityKeeper.CreatePosition(s.Ctx, pool.GetId(), owner, config.tokensProvided, sdk.ZeroInt(), sdk.ZeroInt(), DefaultLowerTick, DefaultUpperTick)
+				_, amount0Initial, amount1Initial, _, _, _, _, err = concentratedLiquidityKeeper.CreatePosition(s.Ctx, pool.GetId(), owner, config.tokensProvided, sdk.ZeroInt(), sdk.ZeroInt(), DefaultLowerTick, DefaultUpperTick)
 				s.Require().NoError(err)
 			}
 			preSendBalanceSender := s.App.BankKeeper.GetAllBalances(s.Ctx, owner)
 
 			if !tc.lastPositionInPool {
 				s.FundAcc(s.TestAccs[1], fundCoins)
-				_, _, _, _, _, err = concentratedLiquidityKeeper.CreatePosition(s.Ctx, pool.GetId(), s.TestAccs[1], config.tokensProvided, sdk.ZeroInt(), sdk.ZeroInt(), DefaultLowerTick, DefaultUpperTick)
+				_, _, _, _, _, _, _, err = concentratedLiquidityKeeper.CreatePosition(s.Ctx, pool.GetId(), s.TestAccs[1], config.tokensProvided, sdk.ZeroInt(), sdk.ZeroInt(), DefaultLowerTick, DefaultUpperTick)
 				s.Require().NoError(err)
 			}
 
@@ -1059,6 +1088,12 @@ func mergeConfigs(dst *lpTest, overwrite *lpTest) {
 		if overwrite.underlyingLockId != 0 {
 			dst.underlyingLockId = overwrite.underlyingLockId
 		}
+		if overwrite.expectedLowerTick != 0 {
+			dst.expectedLowerTick = overwrite.expectedLowerTick
+		}
+		if overwrite.expectedUpperTick != 0 {
+			dst.expectedUpperTick = overwrite.expectedUpperTick
+		}
 	}
 }
 
@@ -1323,7 +1358,7 @@ func (s *KeeperTestSuite) TestUpdatePosition() {
 			// create position
 			// Fund test account and create the desired position
 			s.FundAcc(s.TestAccs[0], DefaultCoins)
-			_, _, _, _, _, err := s.App.ConcentratedLiquidityKeeper.CreatePosition(
+			_, _, _, _, _, _, _, err := s.App.ConcentratedLiquidityKeeper.CreatePosition(
 				s.Ctx,
 				1,
 				s.TestAccs[0],
@@ -1489,6 +1524,17 @@ func (s *KeeperTestSuite) TestInitializeInitialPositionForPool() {
 }
 
 func (s *KeeperTestSuite) TestInverseRelation_CreatePosition_WithdrawPosition() {
+	var (
+		errToleranceOneRoundDown = osmomath.ErrTolerance{
+			AdditiveTolerance: sdk.OneDec(),
+			RoundingDir:       osmomath.RoundDown,
+		}
+
+		errToleranceOneRoundUp = osmomath.ErrTolerance{
+			AdditiveTolerance: sdk.OneDec(),
+			RoundingDir:       osmomath.RoundUp,
+		}
+	)
 	tests := map[string]lpTest{}
 
 	// add test cases for different positions
@@ -1539,9 +1585,18 @@ func (s *KeeperTestSuite) TestInverseRelation_CreatePosition_WithdrawPosition()
 			poolBalancePrePositionCreation := s.App.BankKeeper.GetAllBalances(s.Ctx, poolBefore.GetAddress())
 
 			// System under test.
-			positionId, amtDenom0CreatePosition, amtDenom1CreatePosition, liquidityCreated, _, err := clKeeper.CreatePosition(s.Ctx, tc.poolId, s.TestAccs[0], tc.tokensProvided, tc.amount0Minimum, tc.amount1Minimum, tc.lowerTick, tc.upperTick)
+			positionId, amtDenom0CreatePosition, amtDenom1CreatePosition, liquidityCreated, _, newLowerTick, newUpperTick, err := clKeeper.CreatePosition(s.Ctx, tc.poolId, s.TestAccs[0], tc.tokensProvided, tc.amount0Minimum, tc.amount1Minimum, tc.lowerTick, tc.upperTick)
 			s.Require().NoError(err)
 
+			if tc.expectedLowerTick != 0 {
+				s.Require().Equal(tc.expectedLowerTick, newLowerTick)
+				tc.lowerTick = newLowerTick
+			}
+			if tc.expectedUpperTick != 0 {
+				s.Require().Equal(tc.expectedUpperTick, newUpperTick)
+				tc.upperTick = newUpperTick
+			}
+
 			s.Ctx = s.Ctx.WithBlockTime(DefaultJoinTime.Add(time.Hour * 24))
 			amtDenom0WithdrawPosition, amtDenom1WithdrawPosition, err := clKeeper.WithdrawPosition(s.Ctx, s.TestAccs[0], positionId, liquidityCreated)
 			s.Require().NoError(err)
@@ -1549,21 +1604,21 @@ func (s *KeeperTestSuite) TestInverseRelation_CreatePosition_WithdrawPosition()
 			// INVARIANTS
 
 			// 1. amount for denom0 and denom1 upon creating and withdraw position should be same
-			// Note: subtracting one because create position rounds in favor of the pool.
-			s.Require().Equal(amtDenom0CreatePosition.Sub(sdk.OneInt()).String(), amtDenom0WithdrawPosition.String())
-			s.Require().Equal(amtDenom1CreatePosition.Sub(sdk.OneInt()).String(), amtDenom1WithdrawPosition.String())
+			// Note: round down because create position rounds in favor of the pool.
+			s.Require().Equal(0, errToleranceOneRoundDown.Compare(amtDenom0CreatePosition, amtDenom0WithdrawPosition))
+			s.Require().Equal(0, errToleranceOneRoundDown.Compare(amtDenom1CreatePosition, amtDenom1WithdrawPosition))
 
 			// 2. user balance and pool balance after creating / withdrawing position should be same
 			userBalancePostPositionCreation := s.App.BankKeeper.GetAllBalances(s.Ctx, s.TestAccs[0])
 			poolBalancePostPositionCreation := s.App.BankKeeper.GetAllBalances(s.Ctx, poolBefore.GetAddress())
 
-			// Note: subtracting one since position creation rounds in favor of the pool.
-			s.Require().Equal(userBalancePrePositionCreation.AmountOf(ETH).Sub(sdk.OneInt()).String(), userBalancePostPositionCreation.AmountOf(ETH).String())
-			s.Require().Equal(userBalancePrePositionCreation.AmountOf(USDC).Sub(sdk.OneInt()).String(), userBalancePostPositionCreation.AmountOf(USDC).String())
+			// Note: rounding down since position creation rounds in favor of the pool.
+			s.Require().Equal(0, errToleranceOneRoundDown.Compare(userBalancePrePositionCreation.AmountOf(ETH), userBalancePostPositionCreation.AmountOf(ETH)))
+			s.Require().Equal(0, errToleranceOneRoundDown.Compare(userBalancePrePositionCreation.AmountOf(USDC), userBalancePostPositionCreation.AmountOf(USDC)))
 
-			// Note: adding one since withdrawal rounds in favor of the pool.
-			s.Require().Equal(poolBalancePrePositionCreation.AmountOf(ETH).Add(roundingError).String(), poolBalancePostPositionCreation.AmountOf(ETH).String())
-			s.Require().Equal(poolBalancePrePositionCreation.AmountOf(USDC).Add(roundingError).String(), poolBalancePostPositionCreation.AmountOf(USDC).String())
+			// Note: rounding up since withdrawal rounds in favor of the pool.
+			s.Require().Equal(0, errToleranceOneRoundUp.Compare(poolBalancePrePositionCreation.AmountOf(ETH), poolBalancePostPositionCreation.AmountOf(ETH)))
+			s.Require().Equal(0, errToleranceOneRoundUp.Compare(poolBalancePrePositionCreation.AmountOf(USDC), poolBalancePostPositionCreation.AmountOf(USDC)))
 
 			// 3. Check that position's liquidity was deleted
 			positionLiquidity, err := clKeeper.GetPositionLiquidity(s.Ctx, tc.positionId)
@@ -1579,8 +1634,8 @@ func (s *KeeperTestSuite) TestInverseRelation_CreatePosition_WithdrawPosition()
 			s.Require().NoError(err)
 
 			// Note: one ends up remaining due to rounding in favor of the pool.
-			s.Require().Equal(liquidityBefore.AmountOf(ETH).Add(roundingError).String(), liquidityAfter.AmountOf(ETH).String())
-			s.Require().Equal(liquidityBefore.AmountOf(USDC).Add(roundingError).String(), liquidityAfter.AmountOf(USDC).String())
+			s.Require().Equal(0, errToleranceOneRoundUp.Compare(liquidityBefore.AmountOf(ETH), liquidityAfter.AmountOf(ETH)))
+			s.Require().Equal(0, errToleranceOneRoundUp.Compare(liquidityBefore.AmountOf(USDC), liquidityAfter.AmountOf(USDC)))
 		})
 	}
 }
diff --git a/x/concentrated-liquidity/math/tick_test.go b/x/concentrated-liquidity/math/tick_test.go
index c37ff7ac4..18eb73bd0 100644
--- a/x/concentrated-liquidity/math/tick_test.go
+++ b/x/concentrated-liquidity/math/tick_test.go
@@ -182,7 +182,7 @@ func (suite *ConcentratedMathTestSuite) TestTickToSqrtPrice() {
 	for name, tc := range testCases {
 		tc := tc
 		suite.Run(name, func() {
-			sqrtPrice, err := math.TickToSqrtPrice(tc.tickIndex)
+			price, sqrtPrice, err := math.TickToSqrtPrice(tc.tickIndex)
 			if tc.expectedError != nil {
 				suite.Require().Error(err)
 				suite.Require().Equal(tc.expectedError.Error(), err.Error())
@@ -192,6 +192,7 @@ func (suite *ConcentratedMathTestSuite) TestTickToSqrtPrice() {
 			expectedSqrtPrice, err := tc.expectedPrice.ApproxSqrt()
 			suite.Require().NoError(err)
 
+			suite.Require().Equal(tc.expectedPrice.String(), price.String())
 			suite.Require().Equal(expectedSqrtPrice.String(), sqrtPrice.String())
 		})
 	}
@@ -249,7 +250,7 @@ func (suite *ConcentratedMathTestSuite) TestTicksToSqrtPrice() {
 	for name, tc := range testCases {
 		tc := tc
 		suite.Run(name, func() {
-			lowerSqrtPrice, upperSqrtPrice, err := math.TicksToSqrtPrice(tc.lowerTickIndex.Int64(), tc.upperTickIndex.Int64())
+			priceLower, priceUpper, lowerSqrtPrice, upperSqrtPrice, err := math.TicksToSqrtPrice(tc.lowerTickIndex.Int64(), tc.upperTickIndex.Int64())
 			if tc.expectedError != nil {
 				suite.Require().Error(err)
 				suite.Require().Equal(tc.expectedError.Error(), err.Error())
@@ -263,6 +264,8 @@ func (suite *ConcentratedMathTestSuite) TestTicksToSqrtPrice() {
 			expectedUpperSqrtPrice, err := tc.expectedUpperPrice.ApproxSqrt()
 			suite.Require().NoError(err)
 
+			suite.Require().Equal(tc.expectedLowerPrice.String(), priceLower.String())
+			suite.Require().Equal(tc.expectedUpperPrice.String(), priceUpper.String())
 			suite.Require().Equal(expectedLowerSqrtPrice.String(), lowerSqrtPrice.String())
 			suite.Require().Equal(expectedUpperSqrtPrice.String(), upperSqrtPrice.String())
 		})
@@ -577,7 +580,7 @@ func (suite *ConcentratedMathTestSuite) TestTickToSqrtPricePriceToTick_InverseRe
 			suite.Require().Equal(tickFromPrice.String(), inverseTickFromPrice.String())
 
 			// 4. Validate PriceToTick and TickToSqrtPrice functions
-			sqrtPrice, err := math.TickToSqrtPrice(tickFromPrice)
+			_, sqrtPrice, err := math.TickToSqrtPrice(tickFromPrice)
 			suite.Require().NoError(err)
 
 			priceFromSqrtPrice := sqrtPrice.Power(2)
diff --git a/x/concentrated-liquidity/model/pool_test.go b/x/concentrated-liquidity/model/pool_test.go
index 678d0f70d..0a532cb43 100644
--- a/x/concentrated-liquidity/model/pool_test.go
+++ b/x/concentrated-liquidity/model/pool_test.go
@@ -406,7 +406,7 @@ func (s *ConcentratedPoolTestSuite) TestNewConcentratedLiquidityPool() {
 func (suite *ConcentratedPoolTestSuite) TestCalcActualAmounts() {
 	var (
 		tickToSqrtPrice = func(tick int64) sdk.Dec {
-			sqrtPrice, err := clmath.TickToSqrtPrice(sdk.NewInt(tick))
+			_, sqrtPrice, err := clmath.TickToSqrtPrice(sdk.NewInt(tick))
 			suite.Require().NoError(err)
 			return sqrtPrice
 		}
@@ -517,7 +517,7 @@ func (suite *ConcentratedPoolTestSuite) TestCalcActualAmounts() {
 			pool := model.Pool{
 				CurrentTick: sdk.NewInt(tc.currentTick),
 			}
-			pool.CurrentSqrtPrice, _ = clmath.TickToSqrtPrice(pool.CurrentTick)
+			_, pool.CurrentSqrtPrice, _ = clmath.TickToSqrtPrice(pool.CurrentTick)
 
 			actualAmount0, actualAmount1, err := pool.CalcActualAmounts(suite.Ctx, tc.lowerTick, tc.upperTick, tc.liquidityDelta)
 
@@ -611,7 +611,7 @@ func (suite *ConcentratedPoolTestSuite) TestUpdateLiquidityIfActivePosition() {
 				CurrentTick:          sdk.NewInt(tc.currentTick),
 				CurrentTickLiquidity: defaultLiquidityAmt,
 			}
-			pool.CurrentSqrtPrice, _ = clmath.TickToSqrtPrice(pool.CurrentTick)
+			_, pool.CurrentSqrtPrice, _ = clmath.TickToSqrtPrice(pool.CurrentTick)
 
 			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/pool_test.go b/x/concentrated-liquidity/pool_test.go
index 95836bf61..1a5a2a2e1 100644
--- a/x/concentrated-liquidity/pool_test.go
+++ b/x/concentrated-liquidity/pool_test.go
@@ -481,11 +481,11 @@ func (s *KeeperTestSuite) TestDecreaseConcentratedPoolTickSpacing() {
 			concentratedPool := s.PrepareConcentratedPoolWithCoinsAndFullRangePosition(ETH, USDC)
 
 			// Create a position in the pool that is divisible by the tick spacing
-			_, _, _, _, _, err := s.App.ConcentratedLiquidityKeeper.CreatePosition(s.Ctx, concentratedPool.GetId(), owner, DefaultCoins, sdk.ZeroInt(), sdk.ZeroInt(), -100, 100)
+			_, _, _, _, _, _, _, err := s.App.ConcentratedLiquidityKeeper.CreatePosition(s.Ctx, concentratedPool.GetId(), owner, DefaultCoins, sdk.ZeroInt(), sdk.ZeroInt(), -100, 100)
 			s.Require().NoError(err)
 
 			// Attempt to create a position that is not divisible by the tick spacing
-			_, _, _, _, _, err = s.App.ConcentratedLiquidityKeeper.CreatePosition(s.Ctx, concentratedPool.GetId(), owner, DefaultCoins, sdk.ZeroInt(), sdk.ZeroInt(), test.position.lowerTick, test.position.upperTick)
+			_, _, _, _, _, _, _, err = s.App.ConcentratedLiquidityKeeper.CreatePosition(s.Ctx, concentratedPool.GetId(), owner, DefaultCoins, sdk.ZeroInt(), sdk.ZeroInt(), test.position.lowerTick, test.position.upperTick)
 			s.Require().Error(err)
 
 			// Alter the tick spacing of the pool
@@ -498,7 +498,7 @@ func (s *KeeperTestSuite) TestDecreaseConcentratedPoolTickSpacing() {
 			s.Require().NoError(err)
 
 			// Attempt to create a position that was previously not divisible by the tick spacing but now is
-			_, _, _, _, _, err = s.App.ConcentratedLiquidityKeeper.CreatePosition(s.Ctx, concentratedPool.GetId(), owner, DefaultCoins, sdk.ZeroInt(), sdk.ZeroInt(), test.position.lowerTick, test.position.upperTick)
+			_, _, _, _, _, _, _, err = s.App.ConcentratedLiquidityKeeper.CreatePosition(s.Ctx, concentratedPool.GetId(), owner, DefaultCoins, sdk.ZeroInt(), sdk.ZeroInt(), test.position.lowerTick, test.position.upperTick)
 			if test.expectedCreatePositionErr != nil {
 				s.Require().Error(err)
 				s.Require().ErrorContains(err, test.expectedCreatePositionErr.Error())
diff --git a/x/concentrated-liquidity/position_test.go b/x/concentrated-liquidity/position_test.go
index 70d5e0d3c..524c1a555 100644
--- a/x/concentrated-liquidity/position_test.go
+++ b/x/concentrated-liquidity/position_test.go
@@ -651,12 +651,12 @@ func (s *KeeperTestSuite) TestCalculateUnderlyingAssetsFromPosition() {
 			// prepare concentrated pool with a default position
 			s.PrepareConcentratedPool()
 			s.FundAcc(s.TestAccs[0], sdk.NewCoins(sdk.NewCoin(ETH, DefaultAmt0), sdk.NewCoin(USDC, DefaultAmt1)))
-			_, _, _, _, _, err := s.App.ConcentratedLiquidityKeeper.CreatePosition(s.Ctx, 1, s.TestAccs[0], DefaultCoins, sdk.ZeroInt(), sdk.ZeroInt(), DefaultLowerTick, DefaultUpperTick)
+			_, _, _, _, _, _, _, err := s.App.ConcentratedLiquidityKeeper.CreatePosition(s.Ctx, 1, s.TestAccs[0], DefaultCoins, sdk.ZeroInt(), sdk.ZeroInt(), DefaultLowerTick, DefaultUpperTick)
 			s.Require().NoError(err)
 
 			// create a position from the test case
 			s.FundAcc(s.TestAccs[1], sdk.NewCoins(sdk.NewCoin(ETH, DefaultAmt0), sdk.NewCoin(USDC, DefaultAmt1)))
-			_, actualAmount0, actualAmount1, liquidity, _, err := s.App.ConcentratedLiquidityKeeper.CreatePosition(s.Ctx, tc.position.PoolId, s.TestAccs[1], DefaultCoins, sdk.ZeroInt(), sdk.ZeroInt(), tc.position.LowerTick, tc.position.UpperTick)
+			_, actualAmount0, actualAmount1, liquidity, _, _, _, err := s.App.ConcentratedLiquidityKeeper.CreatePosition(s.Ctx, tc.position.PoolId, s.TestAccs[1], DefaultCoins, sdk.ZeroInt(), sdk.ZeroInt(), tc.position.LowerTick, tc.position.UpperTick)
 			s.Require().NoError(err)
 			tc.position.Liquidity = liquidity
 
@@ -858,7 +858,7 @@ func (s *KeeperTestSuite) TestValidateAndFungifyChargedPositions() {
 					_, _, _, liquidityCreated, _, _, err = s.App.ConcentratedLiquidityKeeper.CreateFullRangePositionUnlocking(s.Ctx, pos.poolId, pos.acc, pos.coins, lockDuration)
 					s.Require().NoError(err)
 				} else {
-					_, _, _, liquidityCreated, _, err = s.App.ConcentratedLiquidityKeeper.CreatePosition(s.Ctx, pos.poolId, pos.acc, pos.coins, sdk.ZeroInt(), sdk.ZeroInt(), pos.lowerTick, pos.upperTick)
+					_, _, _, liquidityCreated, _, _, _, err = s.App.ConcentratedLiquidityKeeper.CreatePosition(s.Ctx, pos.poolId, pos.acc, pos.coins, sdk.ZeroInt(), sdk.ZeroInt(), pos.lowerTick, pos.upperTick)
 					s.Require().NoError(err)
 				}
 
@@ -870,7 +870,7 @@ func (s *KeeperTestSuite) TestValidateAndFungifyChargedPositions() {
 
 			// Set up uncharged positions
 			for _, pos := range test.setupUnchargedPositions {
-				_, _, _, _, _, err := s.App.ConcentratedLiquidityKeeper.CreatePosition(s.Ctx, pos.poolId, pos.acc, pos.coins, sdk.ZeroInt(), sdk.ZeroInt(), pos.lowerTick, pos.upperTick)
+				_, _, _, _, _, _, _, err := s.App.ConcentratedLiquidityKeeper.CreatePosition(s.Ctx, pos.poolId, pos.acc, pos.coins, sdk.ZeroInt(), sdk.ZeroInt(), pos.lowerTick, pos.upperTick)
 				s.Require().NoError(err)
 			}
 
@@ -1178,7 +1178,7 @@ func (s *KeeperTestSuite) TestFungifyChargedPositions_SwapAndClaimFees() {
 	// Set up fully charged positions
 	totalLiquidity := sdk.ZeroDec()
 	for i := 0; i < numPositions; i++ {
-		_, _, _, liquidityCreated, _, err := s.App.ConcentratedLiquidityKeeper.CreatePosition(s.Ctx, defaultPoolId, defaultAddress, DefaultCoins, sdk.ZeroInt(), sdk.ZeroInt(), DefaultLowerTick, DefaultUpperTick)
+		_, _, _, liquidityCreated, _, _, _, err := s.App.ConcentratedLiquidityKeeper.CreatePosition(s.Ctx, defaultPoolId, defaultAddress, DefaultCoins, sdk.ZeroInt(), sdk.ZeroInt(), DefaultLowerTick, DefaultUpperTick)
 		s.Require().NoError(err)
 		totalLiquidity = totalLiquidity.Add(liquidityCreated)
 	}
@@ -1293,7 +1293,7 @@ func (s *KeeperTestSuite) TestFungifyChargedPositions_ClaimIncentives() {
 	// Set up fully charged positions
 	totalLiquidity := sdk.ZeroDec()
 	for i := 0; i < numPositions; i++ {
-		_, _, _, liquidityCreated, _, err := s.App.ConcentratedLiquidityKeeper.CreatePosition(s.Ctx, defaultPoolId, defaultAddress, DefaultCoins, sdk.ZeroInt(), sdk.ZeroInt(), DefaultLowerTick, DefaultUpperTick)
+		_, _, _, liquidityCreated, _, _, _, err := s.App.ConcentratedLiquidityKeeper.CreatePosition(s.Ctx, defaultPoolId, defaultAddress, DefaultCoins, sdk.ZeroInt(), sdk.ZeroInt(), DefaultLowerTick, DefaultUpperTick)
 		s.Require().NoError(err)
 		totalLiquidity = totalLiquidity.Add(liquidityCreated)
 	}
@@ -1515,7 +1515,7 @@ func (s *KeeperTestSuite) TestMintSharesLockAndUpdate() {
 				s.Require().NoError(err)
 			} else {
 				var err error
-				positionId, _, _, liquidity, _, err = s.App.ConcentratedLiquidityKeeper.CreatePosition(s.Ctx, clPool.GetId(), test.owner, defaultPositionCoins, sdk.ZeroInt(), sdk.ZeroInt(), DefaultLowerTick, DefaultUpperTick)
+				positionId, _, _, liquidity, _, _, _, err = s.App.ConcentratedLiquidityKeeper.CreatePosition(s.Ctx, clPool.GetId(), test.owner, defaultPositionCoins, sdk.ZeroInt(), sdk.ZeroInt(), DefaultLowerTick, DefaultUpperTick)
 				s.Require().NoError(err)
 			}
 
@@ -1990,7 +1990,7 @@ func (s *KeeperTestSuite) TestGetAndUpdateFullRangeLiquidity() {
 
 		// Create a new position that overlaps with the min tick, but is not full range and therefore should not count towards the full range liquidity.
 		s.FundAcc(owner, tc.positionCoins)
-		_, _, _, _, _, err = s.App.ConcentratedLiquidityKeeper.CreatePosition(s.Ctx, clPoolId, owner, DefaultCoins, sdk.ZeroInt(), sdk.ZeroInt(), tc.lowerTick, tc.upperTick)
+		_, _, _, _, _, _, _, err = s.App.ConcentratedLiquidityKeeper.CreatePosition(s.Ctx, clPoolId, owner, DefaultCoins, sdk.ZeroInt(), sdk.ZeroInt(), tc.lowerTick, tc.upperTick)
 		s.Require().NoError(err)
 
 		clPool, err = s.App.ConcentratedLiquidityKeeper.GetPoolById(s.Ctx, clPoolId)
diff --git a/x/concentrated-liquidity/swaps_test.go b/x/concentrated-liquidity/swaps_test.go
index a1285e502..cc4bd8923 100644
--- a/x/concentrated-liquidity/swaps_test.go
+++ b/x/concentrated-liquidity/swaps_test.go
@@ -1477,7 +1477,7 @@ func (s *KeeperTestSuite) TestCalcAndSwapOutAmtGivenIn() {
 				newUpperTick, err := math.PriceToTickRoundDown(test.secondPositionUpperPrice, pool.GetTickSpacing())
 				s.Require().NoError(err)
 
-				_, _, _, _, _, err = s.App.ConcentratedLiquidityKeeper.CreatePosition(s.Ctx, pool.GetId(), s.TestAccs[1], DefaultCoins, sdk.ZeroInt(), sdk.ZeroInt(), newLowerTick.Int64(), newUpperTick.Int64())
+				_, _, _, _, _, _, _, err = s.App.ConcentratedLiquidityKeeper.CreatePosition(s.Ctx, pool.GetId(), s.TestAccs[1], DefaultCoins, sdk.ZeroInt(), sdk.ZeroInt(), newLowerTick.Int64(), newUpperTick.Int64())
 				s.Require().NoError(err)
 			}
 
@@ -1511,9 +1511,9 @@ func (s *KeeperTestSuite) TestCalcAndSwapOutAmtGivenIn() {
 				newUpperTick, err := math.PriceToTickRoundDown(test.newUpperPrice, pool.GetTickSpacing())
 				s.Require().NoError(err)
 
-				lowerSqrtPrice, err := math.TickToSqrtPrice(newLowerTick)
+				_, lowerSqrtPrice, err := math.TickToSqrtPrice(newLowerTick)
 				s.Require().NoError(err)
-				upperSqrtPrice, err := math.TickToSqrtPrice(newUpperTick)
+				_, upperSqrtPrice, err := math.TickToSqrtPrice(newUpperTick)
 				s.Require().NoError(err)
 
 				if test.poolLiqAmount0.IsNil() && test.poolLiqAmount1.IsNil() {
@@ -1562,9 +1562,9 @@ func (s *KeeperTestSuite) TestCalcAndSwapOutAmtGivenIn() {
 				newUpperTick, err := math.PriceToTickRoundDown(test.newUpperPrice, pool.GetTickSpacing())
 				s.Require().NoError(err)
 
-				lowerSqrtPrice, err := math.TickToSqrtPrice(newLowerTick)
+				_, lowerSqrtPrice, err := math.TickToSqrtPrice(newLowerTick)
 				s.Require().NoError(err)
-				upperSqrtPrice, err := math.TickToSqrtPrice(newUpperTick)
+				_, upperSqrtPrice, err := math.TickToSqrtPrice(newUpperTick)
 				s.Require().NoError(err)
 
 				if test.poolLiqAmount0.IsNil() && test.poolLiqAmount1.IsNil() {
@@ -1627,7 +1627,7 @@ func (s *KeeperTestSuite) TestSwapOutAmtGivenIn_TickUpdates() {
 				newUpperTick, err := math.PriceToTickRoundDown(test.secondPositionUpperPrice, pool.GetTickSpacing())
 				s.Require().NoError(err)
 
-				_, _, _, _, _, err = s.App.ConcentratedLiquidityKeeper.CreatePosition(s.Ctx, pool.GetId(), s.TestAccs[1], DefaultCoins, sdk.ZeroInt(), sdk.ZeroInt(), newLowerTick.Int64(), newUpperTick.Int64())
+				_, _, _, _, _, _, _, err = s.App.ConcentratedLiquidityKeeper.CreatePosition(s.Ctx, pool.GetId(), s.TestAccs[1], DefaultCoins, sdk.ZeroInt(), sdk.ZeroInt(), newLowerTick.Int64(), newUpperTick.Int64())
 				s.Require().NoError(err)
 			}
 
@@ -1709,7 +1709,7 @@ func (s *KeeperTestSuite) TestCalcAndSwapInAmtGivenOut() {
 				newUpperTick, err := math.PriceToTickRoundDown(test.secondPositionUpperPrice, pool.GetTickSpacing())
 				s.Require().NoError(err)
 
-				_, _, _, _, _, err = s.App.ConcentratedLiquidityKeeper.CreatePosition(s.Ctx, pool.GetId(), s.TestAccs[1], DefaultCoins, sdk.ZeroInt(), sdk.ZeroInt(), newLowerTick.Int64(), newUpperTick.Int64())
+				_, _, _, _, _, _, _, err = s.App.ConcentratedLiquidityKeeper.CreatePosition(s.Ctx, pool.GetId(), s.TestAccs[1], DefaultCoins, sdk.ZeroInt(), sdk.ZeroInt(), newLowerTick.Int64(), newUpperTick.Int64())
 				s.Require().NoError(err)
 			}
 
@@ -1742,9 +1742,9 @@ func (s *KeeperTestSuite) TestCalcAndSwapInAmtGivenOut() {
 				newUpperTick, err := math.PriceToTickRoundDown(test.newUpperPrice, pool.GetTickSpacing())
 				s.Require().NoError(err)
 
-				lowerSqrtPrice, err := math.TickToSqrtPrice(newLowerTick)
+				_, lowerSqrtPrice, err := math.TickToSqrtPrice(newLowerTick)
 				s.Require().NoError(err)
-				upperSqrtPrice, err := math.TickToSqrtPrice(newUpperTick)
+				_, upperSqrtPrice, err := math.TickToSqrtPrice(newUpperTick)
 				s.Require().NoError(err)
 
 				if test.poolLiqAmount0.IsNil() && test.poolLiqAmount1.IsNil() {
@@ -1798,9 +1798,9 @@ func (s *KeeperTestSuite) TestCalcAndSwapInAmtGivenOut() {
 				newUpperTick, err := math.PriceToTickRoundDown(test.newUpperPrice, pool.GetTickSpacing())
 				s.Require().NoError(err)
 
-				lowerSqrtPrice, err := math.TickToSqrtPrice(newLowerTick)
+				_, lowerSqrtPrice, err := math.TickToSqrtPrice(newLowerTick)
 				s.Require().NoError(err)
-				upperSqrtPrice, err := math.TickToSqrtPrice(newUpperTick)
+				_, upperSqrtPrice, err := math.TickToSqrtPrice(newUpperTick)
 				s.Require().NoError(err)
 
 				if test.poolLiqAmount0.IsNil() && test.poolLiqAmount1.IsNil() {
@@ -1873,7 +1873,7 @@ func (s *KeeperTestSuite) TestSwapInAmtGivenOut_TickUpdates() {
 				newUpperTick, err := math.PriceToTickRoundDown(test.secondPositionUpperPrice, pool.GetTickSpacing())
 				s.Require().NoError(err)
 
-				_, _, _, _, _, err = s.App.ConcentratedLiquidityKeeper.CreatePosition(s.Ctx, pool.GetId(), s.TestAccs[1], DefaultCoins, sdk.ZeroInt(), sdk.ZeroInt(), newLowerTick.Int64(), newUpperTick.Int64())
+				_, _, _, _, _, _, _, err = s.App.ConcentratedLiquidityKeeper.CreatePosition(s.Ctx, pool.GetId(), s.TestAccs[1], DefaultCoins, sdk.ZeroInt(), sdk.ZeroInt(), newLowerTick.Int64(), newUpperTick.Int64())
 				s.Require().NoError(err)
 			}
 
@@ -2308,7 +2308,7 @@ func (s *KeeperTestSuite) TestCalcOutAmtGivenInWriteCtx() {
 				newUpperTick, err := math.PriceToTickRoundDown(test.secondPositionUpperPrice, pool.GetTickSpacing())
 				s.Require().NoError(err)
 
-				_, _, _, _, _, err = s.App.ConcentratedLiquidityKeeper.CreatePosition(s.Ctx, pool.GetId(), s.TestAccs[1], DefaultCoins, sdk.ZeroInt(), sdk.ZeroInt(), newLowerTick.Int64(), newUpperTick.Int64())
+				_, _, _, _, _, _, _, err = s.App.ConcentratedLiquidityKeeper.CreatePosition(s.Ctx, pool.GetId(), s.TestAccs[1], DefaultCoins, sdk.ZeroInt(), sdk.ZeroInt(), newLowerTick.Int64(), newUpperTick.Int64())
 				s.Require().NoError(err)
 			}
 
@@ -2392,7 +2392,7 @@ func (s *KeeperTestSuite) TestCalcInAmtGivenOutWriteCtx() {
 				newUpperTick, err := math.PriceToTickRoundDown(test.secondPositionUpperPrice, pool.GetTickSpacing())
 				s.Require().NoError(err)
 
-				_, _, _, _, _, err = s.App.ConcentratedLiquidityKeeper.CreatePosition(s.Ctx, pool.GetId(), s.TestAccs[1], DefaultCoins, sdk.ZeroInt(), sdk.ZeroInt(), newLowerTick.Int64(), newUpperTick.Int64())
+				_, _, _, _, _, _, _, err = s.App.ConcentratedLiquidityKeeper.CreatePosition(s.Ctx, pool.GetId(), s.TestAccs[1], DefaultCoins, sdk.ZeroInt(), sdk.ZeroInt(), newLowerTick.Int64(), newUpperTick.Int64())
 				s.Require().NoError(err)
 			}
 
@@ -2468,7 +2468,7 @@ func (s *KeeperTestSuite) TestInverseRelationshipSwapOutAmtGivenIn() {
 				newUpperTick, err := math.PriceToTickRoundDown(test.secondPositionUpperPrice, pool.GetTickSpacing())
 				s.Require().NoError(err)
 
-				_, _, _, _, _, err = s.App.ConcentratedLiquidityKeeper.CreatePosition(s.Ctx, pool.GetId(), s.TestAccs[1], DefaultCoins, sdk.ZeroInt(), sdk.ZeroInt(), newLowerTick.Int64(), newUpperTick.Int64())
+				_, _, _, _, _, _, _, err = s.App.ConcentratedLiquidityKeeper.CreatePosition(s.Ctx, pool.GetId(), s.TestAccs[1], DefaultCoins, sdk.ZeroInt(), sdk.ZeroInt(), newLowerTick.Int64(), newUpperTick.Int64())
 				s.Require().NoError(err)
 			}
 
@@ -2566,7 +2566,7 @@ func (s *KeeperTestSuite) TestInverseRelationshipSwapInAmtGivenOut() {
 				newUpperTick, err := math.PriceToTickRoundDown(test.secondPositionUpperPrice, pool.GetTickSpacing())
 				s.Require().NoError(err)
 
-				_, _, _, _, _, err = s.App.ConcentratedLiquidityKeeper.CreatePosition(s.Ctx, pool.GetId(), s.TestAccs[1], DefaultCoins, sdk.ZeroInt(), sdk.ZeroInt(), newLowerTick.Int64(), newUpperTick.Int64())
+				_, _, _, _, _, _, _, err = s.App.ConcentratedLiquidityKeeper.CreatePosition(s.Ctx, pool.GetId(), s.TestAccs[1], DefaultCoins, sdk.ZeroInt(), sdk.ZeroInt(), newLowerTick.Int64(), newUpperTick.Int64())
 				s.Require().NoError(err)
 			}
 
diff --git a/x/concentrated-liquidity/tick_test.go b/x/concentrated-liquidity/tick_test.go
index e347cd611..21a802e70 100644
--- a/x/concentrated-liquidity/tick_test.go
+++ b/x/concentrated-liquidity/tick_test.go
@@ -571,7 +571,7 @@ func (s *KeeperTestSuite) TestCrossTick() {
 
 			if test.poolToGet == validPoolId {
 				s.FundAcc(s.TestAccs[0], sdk.NewCoins(DefaultCoin0, DefaultCoin1))
-				_, _, _, _, _, err := s.App.ConcentratedLiquidityKeeper.CreatePosition(s.Ctx, test.poolToGet, s.TestAccs[0], DefaultCoins, sdk.ZeroInt(), sdk.ZeroInt(), DefaultLowerTick, DefaultUpperTick)
+				_, _, _, _, _, _, _, err := s.App.ConcentratedLiquidityKeeper.CreatePosition(s.Ctx, test.poolToGet, s.TestAccs[0], DefaultCoins, sdk.ZeroInt(), sdk.ZeroInt(), DefaultLowerTick, DefaultUpperTick)
 				s.Require().NoError(err)
 			}
 
@@ -1180,7 +1180,7 @@ func (s *KeeperTestSuite) TestGetTickLiquidityNetInDirection() {
 			curTick, err := math.PriceToTick(curPrice)
 			s.Require().NoError(err)
 			if !test.currentPoolTick.IsNil() {
-				sqrtPrice, err := math.TickToSqrtPrice(test.currentPoolTick)
+				_, sqrtPrice, err := math.TickToSqrtPrice(test.currentPoolTick)
 				s.Require().NoError(err)
 
 				curTick = test.currentPoolTick
@@ -1407,3 +1407,89 @@ func (s *KeeperTestSuite) TestGetAllInitializedTicksForPool() {
 		})
 	}
 }
+
+func (s *KeeperTestSuite) TestRoundTickToCanonicalPriceTick() {
+	tests := []struct {
+		name                 string
+		lowerTick            int64
+		upperTick            int64
+		expectedNewLowerTick int64
+		expectedNewUpperTick int64
+		expectedError        error
+	}{
+		{
+			name:                 "exact upper tick for 0.000000000000000003 to exact lower tick for 0.000000000000000002",
+			lowerTick:            -161000000,
+			expectedNewLowerTick: -161000000,
+			upperTick:            -160000000,
+			expectedNewUpperTick: -160000000,
+		},
+		{
+			name:                 "exact upper tick for 0.000000000000000003 to inexact lower tick for 0.000000000000000002",
+			lowerTick:            -161001234,
+			expectedNewLowerTick: -161000000,
+			upperTick:            -160000000,
+			expectedNewUpperTick: -160000000,
+		},
+		{
+			name:                 "inexact upper tick for 0.000000000000000003 to exact lower tick for 0.000000000000000002",
+			lowerTick:            -161000000,
+			expectedNewLowerTick: -161000000,
+			upperTick:            -160001234,
+			expectedNewUpperTick: -160000000,
+		},
+		{
+			name:                 "inexact upper tick for 0.000000000000000003 to inexact lower tick for 0.000000000000000002",
+			lowerTick:            -161001234,
+			expectedNewLowerTick: -161000000,
+			upperTick:            -160001234,
+			expectedNewUpperTick: -160000000,
+		},
+		{
+			name:                 "upper tick one tick away from lower tick",
+			lowerTick:            -161001234,
+			expectedNewLowerTick: -161000000,
+			upperTick:            -160999999,
+			expectedNewUpperTick: -160000000,
+		},
+		{
+			name:                 "error: new upper tick is lower than new lower tick",
+			lowerTick:            -160001234,
+			expectedNewLowerTick: -160000000,
+			upperTick:            -161001234,
+			expectedNewUpperTick: -161000000,
+			expectedError:        types.InvalidLowerUpperTickError{LowerTick: -160000000, UpperTick: -161000000},
+		},
+		{
+			name:                 "error: new upper tick is the same as new lower tick",
+			lowerTick:            -160001234,
+			expectedNewLowerTick: -160000000,
+			upperTick:            -160000000,
+			expectedNewUpperTick: -160000000,
+			expectedError:        types.InvalidLowerUpperTickError{LowerTick: -160000000, UpperTick: -160000000},
+		},
+	}
+
+	for _, test := range tests {
+		s.Run(test.name, func() {
+			s.SetupTest()
+
+			priceTickLower, _, err := cl.TickToSqrtPrice(sdk.NewInt(test.lowerTick))
+			s.Require().NoError(err)
+			priceTickUpper, _, err := cl.TickToSqrtPrice(sdk.NewInt(test.upperTick))
+			s.Require().NoError(err)
+
+			// System Under Test
+			newLowerTick, newUpperTick, err := cl.RoundTickToCanonicalPriceTick(test.lowerTick, test.upperTick, priceTickLower, priceTickUpper, DefaultTickSpacing)
+
+			if test.expectedError != nil {
+				s.Require().Error(err)
+				s.Require().ErrorContains(err, test.expectedError.Error())
+			} else {
+				s.Require().NoError(err)
+				s.Require().Equal(test.expectedNewLowerTick, newLowerTick)
+				s.Require().Equal(test.expectedNewUpperTick, newUpperTick)
+			}
+		})
+	}
+}
diff --git a/x/superfluid/keeper/export_test.go b/x/superfluid/keeper/export_test.go
index 8e060af97..87c821c7c 100644
--- a/x/superfluid/keeper/export_test.go
+++ b/x/superfluid/keeper/export_test.go
@@ -7,7 +7,6 @@ import (
 
 	cltypes "github.com/osmosis-labs/osmosis/v15/x/concentrated-liquidity/types"
 	lockuptypes "github.com/osmosis-labs/osmosis/v15/x/lockup/types"
-	"github.com/osmosis-labs/osmosis/v15/x/superfluid/types"
 )
 
 var (
@@ -46,15 +45,3 @@ func (k Keeper) PrepareMigration(ctx sdk.Context, sender sdk.AccAddress, lockId
 func (k Keeper) AddToConcentratedLiquiditySuperfluidPosition(ctx sdk.Context, owner sdk.AccAddress, positionId uint64, amount0Added, amount1Added sdk.Int) (uint64, sdk.Int, sdk.Int, sdk.Dec, uint64, error) {
 	return k.addToConcentratedLiquiditySuperfluidPosition(ctx, owner, positionId, amount0Added, amount1Added)
 }
-
-func (k Keeper) SuperfluidUndelegateToConcentratedPosition(ctx sdk.Context, sender string, gammLockID uint64) (types.SuperfluidIntermediaryAccount, error) {
-	return k.superfluidUndelegateToConcentratedPosition(ctx, sender, gammLockID)
-}
-
-func (k Keeper) ValidateGammLockForSuperfluidStaking(ctx sdk.Context, sender sdk.AccAddress, poolId uint64, lockId uint64) (*lockuptypes.PeriodLock, error) {
-	return k.validateGammLockForSuperfluidStaking(ctx, sender, poolId, lockId)
-}
-
-func (k Keeper) GetExistingLockRemainingDuration(ctx sdk.Context, lock *lockuptypes.PeriodLock) (time.Duration, error) {
-	return k.getExistingLockRemainingDuration(ctx, lock)
-}
diff --git a/x/superfluid/keeper/msg_server_test.go b/x/superfluid/keeper/msg_server_test.go
index 3f1da11de..e7e329ee8 100644
--- a/x/superfluid/keeper/msg_server_test.go
+++ b/x/superfluid/keeper/msg_server_test.go
@@ -473,6 +473,15 @@ func (suite *KeeperTestSuite) TestMsgUnPoolWhitelistedPool_Event() {
 func (suite *KeeperTestSuite) TestUnlockAndMigrateSharesToFullRangeConcentratedPosition_Event() {
 	suite.SetupTest()
 
+	const (
+		token0Denom = "token0"
+	)
+
+	// Update authorized quote denoms with the quote denom relied on by the test
+	concentratedLiquidityParams := suite.App.ConcentratedLiquidityKeeper.GetParams(suite.Ctx)
+	concentratedLiquidityParams.AuthorizedQuoteDenoms = append(concentratedLiquidityParams.AuthorizedQuoteDenoms, token0Denom)
+	suite.App.ConcentratedLiquidityKeeper.SetParams(suite.Ctx, concentratedLiquidityParams)
+
 	msgServer := keeper.NewMsgServerImpl(suite.App.SuperfluidKeeper)
 	suite.FundAcc(suite.TestAccs[0], defaultAcctFunds)
 	fullRangeCoins := sdk.NewCoins(defaultPoolAssets[0].Token, defaultPoolAssets[1].Token)
@@ -480,7 +489,7 @@ func (suite *KeeperTestSuite) TestUnlockAndMigrateSharesToFullRangeConcentratedP
 	// Set validators
 	valAddrs := suite.SetupValidators([]stakingtypes.BondStatus{stakingtypes.Bonded})
 
-	// Set balancer pool (foo and stake) and make its respective gamm share an authorized superfluid asset
+	// Set balancer pool and make its respective gamm share an authorized superfluid asset
 	msg := balancer.NewMsgCreateBalancerPool(suite.TestAccs[0], balancer.PoolParams{
 		SwapFee: sdk.NewDecWithPrec(1, 2),
 		ExitFee: sdk.NewDec(0),
@@ -496,7 +505,7 @@ func (suite *KeeperTestSuite) TestUnlockAndMigrateSharesToFullRangeConcentratedP
 	})
 	suite.Require().NoError(err)
 
-	// Set concentrated pool with the same denoms as the balancer pool (foo and stake)
+	// Set concentrated pool with the same denoms as the balancer pool
 	clPool := suite.PrepareCustomConcentratedPool(suite.TestAccs[0], defaultPoolAssets[0].Token.Denom, defaultPoolAssets[1].Token.Denom, 1, sdk.ZeroDec())
 
 	// Set migration link between the balancer and concentrated pool
@@ -520,8 +529,7 @@ func (suite *KeeperTestSuite) TestUnlockAndMigrateSharesToFullRangeConcentratedP
 	suite.Require().NoError(err)
 
 	// Execute UnlockAndMigrateSharesToFullRangeConcentratedPosition message
-	sender, err := sdk.AccAddressFromBech32(locks[0].Owner)
-	suite.Require().NoError(err)
+	sender, _ := sdk.AccAddressFromBech32(locks[0].Owner)
 	_, err = msgServer.UnlockAndMigrateSharesToFullRangeConcentratedPosition(sdk.WrapSDKContext(suite.Ctx),
 		types.NewMsgUnlockAndMigrateSharesToFullRangeConcentratedPosition(sender, locks[0].ID, locks[0].Coins[0]))
 	suite.Require().NoError(err)
diff --git a/x/superfluid/keeper/unpool_test.go b/x/superfluid/keeper/unpool_test.go
index 86d78dd9e..19433dab9 100644
--- a/x/superfluid/keeper/unpool_test.go
+++ b/x/superfluid/keeper/unpool_test.go
@@ -1,17 +1,14 @@
 package keeper_test
 
 import (
-	"fmt"
 	"time"
 
-	errorsmod "cosmossdk.io/errors"
 	"github.com/cosmos/cosmos-sdk/simapp"
 	sdk "github.com/cosmos/cosmos-sdk/types"
 	stakingtypes "github.com/cosmos/cosmos-sdk/x/staking/types"
 
 	"github.com/osmosis-labs/osmosis/v15/x/gamm/pool-models/balancer"
 	gammtypes "github.com/osmosis-labs/osmosis/v15/x/gamm/types"
-	lockuptypes "github.com/osmosis-labs/osmosis/v15/x/lockup/types"
 	"github.com/osmosis-labs/osmosis/v15/x/superfluid/keeper"
 	"github.com/osmosis-labs/osmosis/v15/x/superfluid/types"
 )
@@ -283,146 +280,3 @@ func (suite *KeeperTestSuite) TestUnpoolAllowedPools_WhiteList() {
 	suite.Error(err)
 	suite.Require().ErrorIs(err, types.ErrPoolNotWhitelisted)
 }
-
-func (suite *KeeperTestSuite) TestValidateGammLockForSuperfluid() {
-	lockCreator := suite.TestAccs[0]
-	nonLockCreator := suite.TestAccs[1]
-	type sendTest struct {
-		fundsToLock       sdk.Coins
-		accountToValidate sdk.AccAddress
-		poolIdToValidate  uint64
-		lockIdToValidate  uint64
-		expectedError     error
-	}
-	testCases := map[string]sendTest{
-		"happy path": {
-			fundsToLock:       sdk.NewCoins(sdk.NewCoin("gamm/pool/1", sdk.NewInt(100))),
-			accountToValidate: lockCreator,
-			poolIdToValidate:  1,
-			lockIdToValidate:  1,
-		},
-		"error: non-existent lock ID": {
-			fundsToLock:       sdk.NewCoins(sdk.NewCoin("gamm/pool/1", sdk.NewInt(100))),
-			accountToValidate: lockCreator,
-			poolIdToValidate:  1,
-			lockIdToValidate:  2,
-			expectedError:     errorsmod.Wrap(lockuptypes.ErrLockupNotFound, fmt.Sprintf("lock with ID %d does not exist", 2)),
-		},
-		"error: mismatched owner": {
-			fundsToLock:       sdk.NewCoins(sdk.NewCoin("gamm/pool/1", sdk.NewInt(100))),
-			accountToValidate: nonLockCreator,
-			poolIdToValidate:  1,
-			lockIdToValidate:  1,
-			expectedError:     lockuptypes.ErrNotLockOwner,
-		},
-		"error: more than one coin in lock": {
-			fundsToLock: sdk.NewCoins(sdk.NewCoin("gamm/pool/1", sdk.NewInt(100)),
-				sdk.NewCoin("gamm/pool/2", sdk.NewInt(100))),
-			accountToValidate: lockCreator,
-			poolIdToValidate:  1,
-			lockIdToValidate:  1,
-			expectedError:     types.ErrMultipleCoinsLockupNotSupported,
-		},
-		"error: wrong pool ID provided when compared to lock denom": {
-			fundsToLock:       sdk.NewCoins(sdk.NewCoin("gamm/pool/1", sdk.NewInt(100))),
-			accountToValidate: lockCreator,
-			poolIdToValidate:  2,
-			lockIdToValidate:  1,
-			expectedError:     types.UnexpectedDenomError{ExpectedDenom: gammtypes.GetPoolShareDenom(2), ProvidedDenom: "gamm/pool/1"},
-		},
-		"error: right pool ID provided but not gamm/pool/ prefix": {
-			fundsToLock:       sdk.NewCoins(sdk.NewCoin("cl/pool/1", sdk.NewInt(100))),
-			accountToValidate: lockCreator,
-			poolIdToValidate:  1,
-			lockIdToValidate:  1,
-			expectedError:     types.UnexpectedDenomError{ExpectedDenom: gammtypes.GetPoolShareDenom(1), ProvidedDenom: "cl/pool/1"},
-		},
-	}
-
-	for name, tc := range testCases {
-		suite.Run(name, func() {
-			suite.SetupTest()
-
-			ctx := suite.Ctx
-			superfluidKeeper := suite.App.SuperfluidKeeper
-
-			suite.FundAcc(lockCreator, tc.fundsToLock)
-			_, err := suite.App.LockupKeeper.CreateLock(ctx, lockCreator, tc.fundsToLock, time.Hour)
-			suite.Require().NoError(err)
-
-			// System under test
-			_, err = superfluidKeeper.ValidateGammLockForSuperfluidStaking(ctx, tc.accountToValidate, tc.poolIdToValidate, tc.lockIdToValidate)
-			if tc.expectedError != nil {
-				suite.Require().Error(err)
-				suite.Require().ErrorContains(err, tc.expectedError.Error())
-				return
-			}
-			suite.Require().NoError(err)
-		})
-	}
-}
-
-func (suite *KeeperTestSuite) TestGetExistingLockRemainingDuration() {
-	defaultJoinTime := suite.Ctx.BlockTime()
-	lockCreator := suite.TestAccs[0]
-	type sendTest struct {
-		isUnlocking               bool
-		lockDuration              time.Duration
-		timePassed                time.Duration
-		expectedRemainingDuration time.Duration
-		expectedError             error
-	}
-	testCases := map[string]sendTest{
-		"lock that is not unlocking": {
-			isUnlocking:               false,
-			lockDuration:              time.Hour,
-			timePassed:                time.Hour,
-			expectedRemainingDuration: time.Hour,
-		},
-		"lock that is unlocking": {
-			isUnlocking:               true,
-			lockDuration:              time.Hour,
-			timePassed:                time.Minute,
-			expectedRemainingDuration: time.Hour - time.Minute,
-		},
-		"error: negative duration": {
-			isUnlocking:   true,
-			lockDuration:  time.Hour,
-			timePassed:    time.Hour + time.Minute,
-			expectedError: types.NegativeDurationError{Duration: -time.Minute},
-		},
-	}
-
-	for name, tc := range testCases {
-		suite.Run(name, func() {
-			suite.SetupTest()
-			ctx := suite.Ctx.WithBlockTime(defaultJoinTime)
-
-			superfluidKeeper := suite.App.SuperfluidKeeper
-
-			suite.FundAcc(lockCreator, defaultAcctFunds)
-			lock, err := suite.App.LockupKeeper.CreateLock(ctx, lockCreator, defaultAcctFunds, tc.lockDuration)
-			suite.Require().NoError(err)
-
-			if tc.isUnlocking {
-				_, err = suite.App.LockupKeeper.BeginUnlock(ctx, lock.ID, defaultAcctFunds)
-				suite.Require().NoError(err)
-			}
-
-			ctx = ctx.WithBlockTime(defaultJoinTime.Add(tc.timePassed))
-
-			lockAfterTime, err := suite.App.LockupKeeper.GetLockByID(ctx, lock.ID)
-			suite.Require().NoError(err)
-
-			// System under test
-			remainingDuration, err := superfluidKeeper.GetExistingLockRemainingDuration(ctx, lockAfterTime)
-			if tc.expectedError != nil {
-				suite.Require().Error(err)
-				suite.Require().ErrorContains(err, tc.expectedError.Error())
-				return
-			}
-			suite.Require().NoError(err)
-			suite.Require().Equal(tc.expectedRemainingDuration, remainingDuration)
-		})
-	}
-}