Repository: osmosis-labs/osmosis
Pull request #3119 (2022-10-24 05:58:07)

feat(osmomath): log2 approximation (backport #2788)
This is an automatic backport of pull request #2788 done by [Mergify](https://mergify.com).
Cherry-pick of 8590b80f184e3b93befdad68196bfde3a6b884d6 has failed:
```
On branch mergify/bp/concentrated-liquidity-main/pr-2788
Your branch is up to date with 'origin/concentrated-liquidity-main'.

You are currently cherry-picking commit 8590b80f.
  (fix conflicts and run "git cherry-pick --continue")
  (use "git cherry-pick --skip" to skip this patch)
  (use "git cherry-pick --abort" to cancel the cherry-pick operation)

Changes to be committed:
	modified:   CHANGELOG.md
	modified:   osmomath/rounding_direction_test.go

Unmerged paths:
  (use "git add <file>..." to mark resolution)
	both modified:   osmomath/decimal.go
	both modified:   osmomath/decimal_test.go
	both added:      osmomath/log2_bench_test.go

```


To fix up this pull request, you can check it out locally. See documentation: https://docs.github.com/en/github/collaborating-with-pull-requests/reviewing-changes-in-pull-requests/checking-out-pull-requests-locally

---


<details>
<summary>Mergify commands and options</summary>

<br />

More conditions and actions can be found in the [documentation](https://docs.mergify.com/).

You can also trigger Mergify actions by commenting on this pull request:

- `@Mergifyio refresh` will re-evaluate the rules
- `@Mergifyio rebase` will rebase this PR on its base branch
- `@Mergifyio update` will merge the base branch into this PR
- `@Mergifyio backport <destination>` will backport this PR on `<destination>` branch

Additionally, on Mergify [dashboard](https://dashboard.mergify.com/) you can:

- look at your merge queues
- generate the Mergify configuration with the config editor.

Finally, you can contact us on https://mergify.com
</details>


Patch:
diff --git a/CHANGELOG.md b/CHANGELOG.md
index 38fcdbd27..ee35bcc74 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -44,6 +44,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
 
 ### Features
 
+* [#2788](https://github.com/osmosis-labs/osmosis/pull/2788) Add logarithm base 2 implementation.
 * [#2739](https://github.com/osmosis-labs/osmosis/pull/2739) Add pool type query
 
 ### Bug fixes
diff --git a/osmomath/decimal.go b/osmomath/decimal.go
index 761238fd5..381729988 100644
--- a/osmomath/decimal.go
+++ b/osmomath/decimal.go
@@ -4,7 +4,6 @@ import (
 	"encoding/json"
 	"errors"
 	"fmt"
-	"math"
 	"math/big"
 	"strconv"
 	"strings"
@@ -31,6 +30,9 @@ const (
 
 	// max number of iterations in ApproxRoot function
 	maxApproxRootIterations = 100
+
+	// max number of iterations in Log2 function
+	maxLog2Iterations = 300
 )
 
 var (
@@ -41,7 +43,9 @@ var (
 	oneInt               = big.NewInt(1)
 	tenInt               = big.NewInt(10)
 
-	log2LookupTable map[uint16]BigDec
+	// initialized in init() since requires
+	// precision to be defined.
+	twoBigDec BigDec
 )
 
 // Decimal errors
@@ -58,27 +62,7 @@ func init() {
 		precisionMultipliers[i] = calcPrecisionMultiplier(int64(i))
 	}
 
-	log2LookupTable = buildLog2LookupTable()
-}
-
-// buildLog2LookupTable returns a lookup table for log values
-// ranging from [1, 2)
-// the keys are multiplied by 10 to simplify the rounding logic
-// in the log function
-func buildLog2LookupTable() map[uint16]BigDec {
-	return map[uint16]BigDec{
-		10000: ZeroDec(),
-		10001: MustNewDecFromStr("0.000144262291094554178391070900057479"),
-		11000: MustNewDecFromStr("0.137503523749934908329043617236402782"),
-		12000: MustNewDecFromStr("0.263034405833793833583419514458426332"),
-		13000: MustNewDecFromStr("0.378511623253729812526493224767304557"),
-		14000: MustNewDecFromStr("0.485426827170241759571649887742440632"),
-		15000: MustNewDecFromStr("0.584962500721156181453738943947816508"),
-		16000: MustNewDecFromStr("0.678071905112637652129680570510609824"),
-		17000: MustNewDecFromStr("0.765534746362977060383746581321014178"),
-		18000: MustNewDecFromStr("0.847996906554950015037158458406242841"),
-		19000: MustNewDecFromStr("0.925999418556223145923199993417444246"),
-	}
+	twoBigDec = NewBigDec(2)
 }
 
 func precisionInt() *big.Int {
@@ -883,54 +867,53 @@ func DecApproxEq(t *testing.T, d1 BigDec, d2 BigDec, tol BigDec) (*testing.T, bo
 	return t, diff.LTE(tol), "expected |d1 - d2| <:\t%v\ngot |d1 - d2| = \t\t%v", tol.String(), diff.String()
 }
 
-// ApproxLog2 returns the approximation of log_2 {x}.
-// Rounds down by truncating and right shifting during
-// calculations.
-func (x BigDec) ApproxLog2() BigDec {
-	if x.LT(OneDec()) {
-		panic(fmt.Sprintf("only supporting values >= 1, given (%s)", x))
+// LogBase2 returns log_2 {x}.
+// Rounds down by truncations during division and right shifting.
+// Accurate up to 32 precision digits.
+// Implementation is based on:
+// https://stm32duinoforum.com/forum/dsp/BinaryLogarithm.pdf
+func (x BigDec) LogBase2() BigDec {
+	// create a new decimal to avoid mutating
+	// the receiver's int buffer.
+	xCopy := ZeroDec()
+	xCopy.i = new(big.Int).Set(x.i)
+	if xCopy.LTE(ZeroDec()) {
+		panic(fmt.Sprintf("log is not defined at <= 0, given (%s)", xCopy))
 	}
 
-	// Normalize x to be 1 <= x < 2
+	// Normalize x to be 1 <= x < 2.
 
 	// y is the exponent that results in a whole multiple of 2.
-	y := int64(0)
-
-	// invariant: x >= 1
-	// while x < 1
-	for x.LT(OneDec()) {
-		x.i = x.i.Lsh(x.i, 1)
-		y = y - 1
-	}
-
-	// invariant: x < 2
-	// while x >= 2
-	twoDec := NewBigDec(2)
-	for x.GTE(twoDec) {
-		x.i = x.i.Rsh(x.i, 1)
-		y = y + 1
-	}
-
-	// exponentiate to simplify truncation necessary for
-	// looking up values in the table.
-	lookupKey := x.MulInt64(10000).TruncateInt()
-	if lookupKey.Equal(NewInt(10001)) {
-		tableValue, found := log2LookupTable[uint16(lookupKey.Int64())]
-		if !found {
-			panic(fmt.Sprintf("no matching value for key (%s) in the lookup table", lookupKey))
-		}
-		return NewBigDec(y).Add(tableValue)
+	y := ZeroDec()
+
+	// repeat until: x >= 1.
+	for xCopy.LT(OneDec()) {
+		xCopy.i.Lsh(xCopy.i, 1)
+		y = y.Sub(OneDec())
 	}
-	lookupKeyInt := lookupKey.ToDec().MustFloat64()
-	roundedLookup := math.Round(lookupKeyInt/1000) * 1000
-	lookupKey, _ = NewIntFromString(fmt.Sprintf("%v", roundedLookup))
-	if lookupKey.GTE(NewInt(20000)) || lookupKey.LT(NewInt(10000)) {
-		panic(fmt.Sprintf("invalid lookup key (%s), must be 10 <= lookup key < 2", lookupKey))
+
+	// repeat until: x < 2.
+	for xCopy.GTE(twoBigDec) {
+		xCopy.i.Rsh(xCopy.i, 1)
+		y = y.Add(OneDec())
 	}
 
-	tableValue, found := log2LookupTable[uint16(lookupKey.Int64())]
-	if !found {
-		panic(fmt.Sprintf("no matching value for key (%s) in the lookup table", lookupKey))
+	b := OneDec().Quo(twoBigDec)
+
+	// N.B. At this point x is a positive real number representing
+	// mantissa of the log. We estimate it using the following
+	// algorithm:
+	// https://stm32duinoforum.com/forum/dsp/BinaryLogarithm.pdf
+	// This has shown precision of 32 digits relative
+	// to Wolfram Alpha in tests.
+	for i := 0; i < maxLog2Iterations; i++ {
+		xCopy = xCopy.Mul(xCopy)
+		if xCopy.GTE(twoBigDec) {
+			xCopy.i.Rsh(xCopy.i, 1)
+			y = y.Add(b)
+		}
+		b.i.Rsh(b.i, 1)
 	}
-	return NewBigDec(y).Add(tableValue)
+
+	return y
 }
diff --git a/proto/osmosis/concentrated-liquidity/concentratedPool.proto b/proto/osmosis/concentrated-liquidity/concentratedPool.proto
index 79e724c48..9ae361db2 100644
--- a/proto/osmosis/concentrated-liquidity/concentratedPool.proto
+++ b/proto/osmosis/concentrated-liquidity/concentratedPool.proto
@@ -11,47 +11,47 @@ import "gogoproto/gogo.proto";
 option go_package = "github.com/osmosis-labs/osmosis/v12/x/concentrated-liquidity";
 
 message Pool {
-  option (gogoproto.goproto_getters)         = false;
-  option (gogoproto.goproto_stringer)        = false;
+  option (gogoproto.goproto_getters) = false;
+  option (gogoproto.goproto_stringer) = false;
   option (cosmos_proto.implements_interface) = "PoolI";
 
-  string address = 1 [(gogoproto.moretags) = "yaml:\"address\""];
-  uint64 id      = 2;
+  string address = 1 [ (gogoproto.moretags) = "yaml:\"address\"" ];
+  uint64 id = 2;
 
   // Amount of total liquidity
   string liquidity = 3 [
     (gogoproto.customtype) = "github.com/cosmos/cosmos-sdk/types.Int",
-    (gogoproto.moretags)   = "yaml:\"liquidity\"",
-    (gogoproto.nullable)   = false
+    (gogoproto.moretags) = "yaml:\"liquidity\"",
+    (gogoproto.nullable) = false
   ];
 
   string token0 = 4;
   string token1 = 5;
 
   string current_sqrt_price = 6 [
-    (gogoproto.customtype) = "github.com/cosmos/cosmos-sdk/types.Int",
-    (gogoproto.moretags)   = "yaml:\"spot_price\"",
-    (gogoproto.nullable)   = false
+    (gogoproto.customtype) = "github.com/cosmos/cosmos-sdk/types.Dec",
+    (gogoproto.moretags) = "yaml:\"spot_price\"",
+    (gogoproto.nullable) = false
   ];
   string current_tick = 7 [
     (gogoproto.customtype) = "github.com/cosmos/cosmos-sdk/types.Int",
-    (gogoproto.moretags)   = "yaml:\"current_tick\"",
-    (gogoproto.nullable)   = false
+    (gogoproto.moretags) = "yaml:\"current_tick\"",
+    (gogoproto.nullable) = false
   ];
 }
 
 message TickInfo {
   string liquidity = 1 [
     (gogoproto.customtype) = "github.com/cosmos/cosmos-sdk/types.Int",
-    (gogoproto.moretags)   = "yaml:\"liquidity\"",
-    (gogoproto.nullable)   = false
+    (gogoproto.moretags) = "yaml:\"liquidity\"",
+    (gogoproto.nullable) = false
   ];
 }
 
 message Position {
   string liquidity = 1 [
     (gogoproto.customtype) = "github.com/cosmos/cosmos-sdk/types.Int",
-    (gogoproto.moretags)   = "yaml:\"liquidity\"",
-    (gogoproto.nullable)   = false
+    (gogoproto.moretags) = "yaml:\"liquidity\"",
+    (gogoproto.nullable) = false
   ];
 }
diff --git a/x/concentrated-liquidity/concentratedPool.pb.go b/x/concentrated-liquidity/concentratedPool.pb.go
index 0e6b3017e..1969343f0 100644
--- a/x/concentrated-liquidity/concentratedPool.pb.go
+++ b/x/concentrated-liquidity/concentratedPool.pb.go
@@ -37,7 +37,7 @@ type Pool struct {
 	Liquidity        github_com_cosmos_cosmos_sdk_types.Int `protobuf:"bytes,3,opt,name=liquidity,proto3,customtype=github.com/cosmos/cosmos-sdk/types.Int" json:"liquidity" yaml:"liquidity"`
 	Token0           string                                 `protobuf:"bytes,4,opt,name=token0,proto3" json:"token0,omitempty"`
 	Token1           string                                 `protobuf:"bytes,5,opt,name=token1,proto3" json:"token1,omitempty"`
-	CurrentSqrtPrice github_com_cosmos_cosmos_sdk_types.Int `protobuf:"bytes,6,opt,name=current_sqrt_price,json=currentSqrtPrice,proto3,customtype=github.com/cosmos/cosmos-sdk/types.Int" json:"current_sqrt_price" yaml:"spot_price"`
+	CurrentSqrtPrice github_com_cosmos_cosmos_sdk_types.Dec `protobuf:"bytes,6,opt,name=current_sqrt_price,json=currentSqrtPrice,proto3,customtype=github.com/cosmos/cosmos-sdk/types.Dec" json:"current_sqrt_price" yaml:"spot_price"`
 	CurrentTick      github_com_cosmos_cosmos_sdk_types.Int `protobuf:"bytes,7,opt,name=current_tick,json=currentTick,proto3,customtype=github.com/cosmos/cosmos-sdk/types.Int" json:"current_tick" yaml:"current_tick"`
 }
 
@@ -158,35 +158,35 @@ func init() {
 }
 
 var fileDescriptor_b144264ce94bcf63 = []byte{
-	// 436 bytes of a gzipped FileDescriptorProto
-	0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xb4, 0x93, 0x31, 0x8e, 0xd3, 0x40,
-	0x14, 0x86, 0xed, 0x6c, 0x36, 0xcb, 0x0e, 0x68, 0xb5, 0x3b, 0x20, 0x64, 0xb6, 0xb0, 0x57, 0x96,
-	0x40, 0x5b, 0x60, 0x1b, 0x83, 0x68, 0x22, 0xaa, 0x20, 0x8a, 0x74, 0x91, 0x41, 0x14, 0x34, 0xc1,
-	0x1e, 0x0f, 0xc9, 0xc8, 0x8e, 0xc7, 0x9e, 0x99, 0x44, 0xe4, 0x06, 0x94, 0x94, 0x94, 0x39, 0x04,
-	0x67, 0x40, 0x11, 0x55, 0x4a, 0x44, 0x61, 0xa1, 0xe4, 0x06, 0x39, 0x01, 0xb2, 0x3d, 0x31, 0x4e,
-	0x41, 0x91, 0x22, 0x95, 0xfd, 0xfe, 0x37, 0xef, 0xff, 0x7e, 0xe9, 0xe9, 0x81, 0x97, 0x94, 0x4f,
-	0x28, 0x27, 0xdc, 0x41, 0x34, 0x41, 0x38, 0x11, 0xcc, 0x17, 0x38, 0xb4, 0x62, 0x92, 0x4d, 0x49,
-	0x48, 0xc4, 0x7c, 0x4f, 0x1e, 0x50, 0x1a, 0xdb, 0x29, 0xa3, 0x82, 0xc2, 0xc7, 0x72, 0xcc, 0x6e,
-	0xf6, 0xeb, 0x29, 0x7b, 0xe6, 0x06, 0x58, 0xf8, 0xee, 0xf5, 0x23, 0x54, 0xbe, 0x1b, 0x96, 0x43,
-	0x4e, 0x55, 0x54, 0x0e, 0xd7, 0x0f, 0x46, 0x74, 0x44, 0x2b, 0xbd, 0xf8, 0xab, 0x54, 0xf3, 0xc7,
-	0x09, 0x68, 0x17, 0x18, 0xf8, 0x14, 0x9c, 0xf9, 0x61, 0xc8, 0x30, 0xe7, 0x9a, 0x7a, 0xa3, 0xde,
-	0x9e, 0xf7, 0xe0, 0x36, 0x37, 0x2e, 0xe6, 0xfe, 0x24, 0xee, 0x9a, 0xb2, 0x61, 0x7a, 0xbb, 0x27,
-	0xf0, 0x02, 0xb4, 0x48, 0xa8, 0xb5, 0x6e, 0xd4, 0xdb, 0xb6, 0xd7, 0x22, 0x21, 0xfc, 0x08, 0xce,
-	0xeb, 0x30, 0xda, 0x49, 0x39, 0xdf, 0x5b, 0xe6, 0x86, 0xf2, 0x3b, 0x37, 0x9e, 0x8c, 0x88, 0x18,
-	0x4f, 0x03, 0x1b, 0xd1, 0x89, 0x0c, 0x24, 0x3f, 0x16, 0x0f, 0x23, 0x47, 0xcc, 0x53, 0xcc, 0xed,
-	0x7e, 0x22, 0xb6, 0xb9, 0x71, 0x59, 0xd1, 0x6a, 0x23, 0xd3, 0xfb, 0x67, 0x0a, 0x1f, 0x82, 0x8e,
-	0xa0, 0x11, 0x4e, 0x9e, 0x69, 0xed, 0xc2, 0xde, 0x93, 0x55, 0xad, 0xbb, 0xda, 0x69, 0x43, 0x77,
-	0x61, 0x06, 0x20, 0x9a, 0x32, 0x86, 0x13, 0x31, 0xe4, 0x19, 0x13, 0xc3, 0x94, 0x11, 0x84, 0xb5,
-	0x4e, 0x19, 0xed, 0xf5, 0xc1, 0xd1, 0xae, 0xaa, 0x68, 0x3c, 0xa5, 0xd2, 0xc9, 0xf4, 0x2e, 0xa5,
-	0xfd, 0xdb, 0x8c, 0x89, 0x41, 0x21, 0xc1, 0x31, 0xb8, 0xb7, 0x43, 0x0a, 0x82, 0x22, 0xed, 0xac,
-	0x84, 0xbd, 0x39, 0x18, 0x76, 0xbf, 0x82, 0x35, 0xbd, 0x4c, 0xef, 0xae, 0x2c, 0xdf, 0x11, 0x14,
-	0x75, 0xaf, 0xbe, 0x2c, 0x0c, 0xe5, 0xdb, 0xc2, 0x50, 0x7e, 0x7e, 0xb7, 0x4e, 0x8b, 0xf5, 0xf5,
-	0xcd, 0x18, 0xdc, 0x29, 0x5a, 0xfd, 0xe4, 0x13, 0xdd, 0xdf, 0x86, 0x7a, 0x84, 0x6d, 0x14, 0xb4,
-	0x01, 0xe5, 0x44, 0x10, 0x9a, 0x1c, 0x9f, 0xd6, 0x7b, 0xbf, 0x5c, 0xeb, 0xea, 0x6a, 0xad, 0xab,
-	0x7f, 0xd6, 0xba, 0xfa, 0x75, 0xa3, 0x2b, 0xab, 0x8d, 0xae, 0xfc, 0xda, 0xe8, 0xca, 0x87, 0x57,
-	0x0d, 0x80, 0xbc, 0x10, 0x2b, 0xf6, 0x03, 0xbe, 0x2b, 0x9c, 0x99, 0xfb, 0xdc, 0xf9, 0xfc, 0x9f,
-	0x5b, 0x0b, 0x3a, 0xe5, 0x0d, 0xbc, 0xf8, 0x1b, 0x00, 0x00, 0xff, 0xff, 0xaa, 0xa3, 0x98, 0x3b,
-	0x94, 0x03, 0x00, 0x00,
+	// 441 bytes of a gzipped FileDescriptorProto
+	0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xb4, 0x53, 0x3d, 0x8e, 0xd3, 0x40,
+	0x14, 0xb6, 0xb3, 0xd9, 0x2c, 0x3b, 0xa0, 0xd5, 0xee, 0x80, 0x90, 0xd9, 0xc2, 0x5e, 0x59, 0x02,
+	0x6d, 0x81, 0x6d, 0x0c, 0xa2, 0x59, 0x51, 0x05, 0x28, 0xd2, 0x45, 0x06, 0x51, 0xd0, 0x04, 0x7b,
+	0x3c, 0x24, 0x23, 0x3b, 0x1e, 0x7b, 0x66, 0x12, 0x91, 0x1b, 0x50, 0x52, 0x52, 0xe6, 0x10, 0x9c,
+	0x01, 0x45, 0x54, 0x29, 0x11, 0x85, 0x85, 0x92, 0x1b, 0xe4, 0x04, 0xc8, 0xf6, 0xc4, 0x38, 0xc5,
+	0x16, 0x29, 0x52, 0xd9, 0xef, 0x7b, 0xef, 0xfb, 0xd1, 0x3c, 0x3d, 0xf0, 0x92, 0xf2, 0x31, 0xe5,
+	0x84, 0x3b, 0x88, 0x26, 0x08, 0x27, 0x82, 0xf9, 0x02, 0x87, 0x56, 0x4c, 0xb2, 0x09, 0x09, 0x89,
+	0x98, 0xed, 0xc0, 0x7d, 0x4a, 0x63, 0x3b, 0x65, 0x54, 0x50, 0xf8, 0x58, 0xd2, 0xec, 0x66, 0xbf,
+	0x66, 0xd9, 0x53, 0x37, 0xc0, 0xc2, 0x77, 0x2f, 0x1f, 0xa1, 0x72, 0x6e, 0x50, 0x92, 0x9c, 0xaa,
+	0xa8, 0x14, 0x2e, 0x1f, 0x0c, 0xe9, 0x90, 0x56, 0x78, 0xf1, 0x57, 0xa1, 0xe6, 0xcf, 0x23, 0xd0,
+	0x2e, 0x6c, 0xe0, 0x53, 0x70, 0xe2, 0x87, 0x21, 0xc3, 0x9c, 0x6b, 0xea, 0x95, 0x7a, 0x7d, 0xda,
+	0x85, 0x9b, 0xdc, 0x38, 0x9b, 0xf9, 0xe3, 0xf8, 0xc6, 0x94, 0x0d, 0xd3, 0xdb, 0x8e, 0xc0, 0x33,
+	0xd0, 0x22, 0xa1, 0xd6, 0xba, 0x52, 0xaf, 0xdb, 0x5e, 0x8b, 0x84, 0xf0, 0x13, 0x38, 0xad, 0xc3,
+	0x68, 0x47, 0x25, 0xbf, 0xbb, 0xc8, 0x0d, 0xe5, 0x4f, 0x6e, 0x3c, 0x19, 0x12, 0x31, 0x9a, 0x04,
+	0x36, 0xa2, 0x63, 0x19, 0x48, 0x7e, 0x2c, 0x1e, 0x46, 0x8e, 0x98, 0xa5, 0x98, 0xdb, 0xbd, 0x44,
+	0x6c, 0x72, 0xe3, 0xbc, 0x72, 0xab, 0x85, 0x4c, 0xef, 0xbf, 0x28, 0x7c, 0x08, 0x3a, 0x82, 0x46,
+	0x38, 0x79, 0xa6, 0xb5, 0x0b, 0x79, 0x4f, 0x56, 0x35, 0xee, 0x6a, 0xc7, 0x0d, 0xdc, 0x85, 0x19,
+	0x80, 0x68, 0xc2, 0x18, 0x4e, 0xc4, 0x80, 0x67, 0x4c, 0x0c, 0x52, 0x46, 0x10, 0xd6, 0x3a, 0x65,
+	0xb4, 0xd7, 0x7b, 0x44, 0x7b, 0x83, 0xd1, 0x26, 0x37, 0x2e, 0xaa, 0x68, 0x3c, 0xa5, 0x52, 0xc9,
+	0xf4, 0xce, 0xa5, 0xfc, 0xbb, 0x8c, 0x89, 0x7e, 0x01, 0xc1, 0x11, 0xb8, 0xb7, 0xb5, 0x14, 0x04,
+	0x45, 0xda, 0x49, 0x69, 0xf6, 0x76, 0xef, 0x77, 0xb8, 0x5f, 0x99, 0x35, 0xb5, 0x4c, 0xef, 0xae,
+	0x2c, 0xdf, 0x13, 0x14, 0xdd, 0x5c, 0x7c, 0x9d, 0x1b, 0xca, 0xf7, 0xb9, 0xa1, 0xfc, 0xfa, 0x61,
+	0x1d, 0x17, 0xeb, 0xeb, 0x99, 0x31, 0xb8, 0x53, 0xb4, 0x7a, 0xc9, 0x67, 0xba, 0xbb, 0x0d, 0xf5,
+	0x00, 0xdb, 0x28, 0xdc, 0xfa, 0x94, 0x13, 0x41, 0x68, 0x72, 0x78, 0xb7, 0xee, 0x87, 0xc5, 0x4a,
+	0x57, 0x97, 0x2b, 0x5d, 0xfd, 0xbb, 0xd2, 0xd5, 0x6f, 0x6b, 0x5d, 0x59, 0xae, 0x75, 0xe5, 0xf7,
+	0x5a, 0x57, 0x3e, 0xbe, 0x6a, 0x18, 0xc8, 0x0b, 0xb1, 0x62, 0x3f, 0xe0, 0xdb, 0xc2, 0x99, 0xba,
+	0xcf, 0x9d, 0x2f, 0xb7, 0xdc, 0x5a, 0xd0, 0x29, 0x6f, 0xe0, 0xc5, 0xbf, 0x00, 0x00, 0x00, 0xff,
+	0xff, 0x76, 0xc8, 0x10, 0x58, 0x94, 0x03, 0x00, 0x00,
 }
 
 func (m *Pool) Marshal() (dAtA []byte, err error) {
diff --git a/x/concentrated-liquidity/lp.go b/x/concentrated-liquidity/lp.go
index 038af7ca2..a1bd7e27f 100644
--- a/x/concentrated-liquidity/lp.go
+++ b/x/concentrated-liquidity/lp.go
@@ -8,7 +8,7 @@ import (
 	types "github.com/osmosis-labs/osmosis/v12/x/concentrated-liquidity/types"
 )
 
-func (k Keeper) Mint(ctx sdk.Context, poolId uint64, owner sdk.AccAddress, liquidityIn sdk.Int, lowerTick, upperTick int64) (amtDenom0, amtDenom1 sdk.Int, err error) {
+func (k Keeper) Mint(ctx sdk.Context, poolId uint64, owner sdk.AccAddress, liquidityIn sdk.Dec, lowerTick, upperTick int64) (amtDenom0, amtDenom1 sdk.Int, err error) {
 	// ensure types.MinTick <= lowerTick < types.MaxTick
 	// TODO (bez): Add unit tests.
 	if lowerTick < types.MinTick || lowerTick >= types.MaxTick {
@@ -24,26 +24,22 @@ func (k Keeper) Mint(ctx sdk.Context, poolId uint64, owner sdk.AccAddress, liqui
 	if liquidityIn.IsZero() {
 		return sdk.Int{}, sdk.Int{}, fmt.Errorf("token in amount is zero")
 	}
-
+	// TODO: we need to check if TickInfo is initialized on a specific tick before updating, otherwise get wont work
+	// k.setTickInfo(ctx, poolId, lowerTick, TickInfo{})
 	// k.UpdateTickWithNewLiquidity(ctx, poolId, lowerTick, liquidityIn)
+	// k.setTickInfo(ctx, poolId, upperTick, TickInfo{})
 	// k.UpdateTickWithNewLiquidity(ctx, poolId, upperTick, liquidityIn)
-
-	// k.updatePositionWithLiquidity(ctx, poolId, owner.String(), lowerTick, upperTick, liquidityIn)
+	// k.setPosition(ctx, poolId, owner, lowerTick, upperTick, Position{})
+	// k.updatePositionWithLiquidity(ctx, poolId, owner, lowerTick, upperTick, liquidityIn)
 
 	pool := k.getPoolbyId(ctx, poolId)
 
 	currentSqrtPrice := pool.CurrentSqrtPrice
-	sqrtRatioUpperTick, err := k.getSqrtRatioAtTick(upperTick)
-	if err != nil {
-		return sdk.Int{}, sdk.Int{}, err
-	}
-	sqrtRatioLowerTick, err := k.getSqrtRatioAtTick(lowerTick)
-	if err != nil {
-		return sdk.Int{}, sdk.Int{}, err
-	}
+	sqrtRatioUpperTick, _ := k.tickToSqrtPrice(sdk.NewInt(upperTick))
+	sqrtRatioLowerTick, _ := k.tickToSqrtPrice(sdk.NewInt(lowerTick))
 
-	amtDenom0 = calcAmount0Delta(currentSqrtPrice.ToDec(), sqrtRatioUpperTick, liquidityIn.ToDec()).RoundInt()
-	amtDenom1 = calcAmount1Delta(currentSqrtPrice.ToDec(), sqrtRatioLowerTick, liquidityIn.ToDec()).RoundInt()
+	amtDenom0 = calcAmount0Delta(liquidityIn, currentSqrtPrice, sqrtRatioUpperTick).RoundInt()
+	amtDenom1 = calcAmount1Delta(liquidityIn, currentSqrtPrice, sqrtRatioLowerTick).RoundInt()
 
 	return amtDenom0, amtDenom1, nil
 }
diff --git a/x/concentrated-liquidity/math.go b/x/concentrated-liquidity/math.go
index 0cc8405df..d35bd59a7 100644
--- a/x/concentrated-liquidity/math.go
+++ b/x/concentrated-liquidity/math.go
@@ -1,6 +1,8 @@
 package concentrated_liquidity
 
-import sdk "github.com/cosmos/cosmos-sdk/types"
+import (
+	sdk "github.com/cosmos/cosmos-sdk/types"
+)
 
 // liquidity0 takes an amount of asset0 in the pool as well as the sqrtpCur and the nextPrice
 // sqrtPriceA is the smaller of sqrtpCur and the nextPrice
@@ -52,3 +54,39 @@ func calcAmount1Delta(liq, sqrtPriceA, sqrtPriceB sdk.Dec) sdk.Dec {
 	diff := sqrtPriceB.Sub(sqrtPriceA)
 	return liq.Mul(diff)
 }
+
+// computeSwapStep calculates the amountIn, amountOut, and the next sqrtPrice given current price, price target, tick liquidity, and amount available to swap
+// lte is reference to "less than or equal", which determines if we are moving left or right of the current price to find the next initialized tick with liquidity
+func computeSwapStep(sqrtPriceCurrent, sqrtPriceTarget, liquidity, amountRemaining sdk.Dec, lte bool) (sqrtPriceNext sdk.Dec, amountIn sdk.Dec, amountOut sdk.Dec) {
+	if lte {
+		sqrtPriceNext = getNextSqrtPriceFromAmount1RoundingDown(sqrtPriceCurrent, liquidity, amountRemaining)
+		amountIn = calcAmount1Delta(liquidity, sqrtPriceNext, sqrtPriceCurrent)
+		amountOut = calcAmount0Delta(liquidity, sqrtPriceNext, sqrtPriceCurrent)
+	} else {
+		sqrtPriceNext = getNextSqrtPriceFromAmount0RoundingUp(sqrtPriceCurrent, liquidity, amountRemaining)
+		amountIn = calcAmount0Delta(liquidity, sqrtPriceNext, sqrtPriceCurrent)
+		amountOut = calcAmount1Delta(liquidity, sqrtPriceNext, sqrtPriceCurrent)
+	}
+	return sqrtPriceNext, amountIn, amountOut
+}
+
+func getNextSqrtPriceFromAmount0RoundingUp(sqrtPriceCurrent, liquidity, amountRemaining sdk.Dec) (sqrtPriceNext sdk.Dec) {
+	numerator := liquidity.Mul(sdk.NewDec(2))
+	product := amountRemaining.Mul(sqrtPriceCurrent)
+
+	if product.Quo(amountRemaining).Equal(sqrtPriceCurrent) {
+		denominator := numerator.Add(product)
+		if denominator.GTE(numerator) {
+			numerator = numerator.Mul(sqrtPriceCurrent)
+			sqrtPriceNext = numerator.QuoRoundUp(denominator)
+			return sqrtPriceNext
+		}
+	}
+	denominator := numerator.Quo(sqrtPriceCurrent).Add(amountRemaining)
+	sqrtPriceNext = numerator.QuoRoundUp(denominator)
+	return sqrtPriceNext
+}
+
+func getNextSqrtPriceFromAmount1RoundingDown(sqrtPriceCurrent, liquidity, amountRemaining sdk.Dec) (sqrtPriceNext sdk.Dec) {
+	return sqrtPriceCurrent.Add(amountRemaining.Quo(liquidity))
+}
diff --git a/x/concentrated-liquidity/pool.go b/x/concentrated-liquidity/pool.go
index dae370331..b54b4461d 100644
--- a/x/concentrated-liquidity/pool.go
+++ b/x/concentrated-liquidity/pool.go
@@ -6,43 +6,37 @@ import (
 	sdk "github.com/cosmos/cosmos-sdk/types"
 
 	"github.com/osmosis-labs/osmosis/v12/osmomath"
+	cltypes "github.com/osmosis-labs/osmosis/v12/x/concentrated-liquidity/types"
 	"github.com/osmosis-labs/osmosis/v12/x/gamm/types"
 )
 
-func (k Keeper) CreateNewConcentratedLiquidityPool(ctx sdk.Context, poolId uint64, denom0, denom1 string, currSqrtPrice, currTick sdk.Int) (Pool, error) {
+func (k Keeper) CreateNewConcentratedLiquidityPool(ctx sdk.Context, poolId uint64, denom0, denom1 string, currSqrtPrice sdk.Dec, currTick sdk.Int) (Pool, error) {
 	poolAddr := types.NewPoolAddress(poolId)
+	denom0, denom1, err := cltypes.OrderInitialPoolDenoms(denom0, denom1)
+	if err != nil {
+		return Pool{}, err
+	}
 	pool := Pool{
 		Address:          poolAddr.String(),
 		Id:               poolId,
 		CurrentSqrtPrice: currSqrtPrice,
 		CurrentTick:      currTick,
+		Token0:           denom0,
+		Token1:           denom1,
 	}
 
 	k.setPoolById(ctx, poolId, pool)
-	err := pool.orderInitialPoolDenoms(denom0, denom1)
-	if err != nil {
-		return Pool{}, err
-	}
 
 	return pool, nil
 }
 
-// TODO: remove nolint
-// nolint: unused
 func priceToTick(price sdk.Dec) sdk.Int {
-	logOfPrice := osmomath.BigDecFromSDKDec(price).ApproxLog2()
+	logOfPrice := osmomath.BigDecFromSDKDec(price).LogBase2()
 	logInt := osmomath.NewDecWithPrec(10001, 4)
-	tick := logOfPrice.Quo(logInt.ApproxLog2())
+	tick := logOfPrice.Quo(logInt.LogBase2())
 	return tick.SDKDec().TruncateInt()
 }
 
-// TODO: remove nolint
-// nolint: unused
-func tickToPrice(tick sdk.Int) sdk.Dec {
-	price := sdk.NewDecWithPrec(10001, 4).Power(tick.Uint64())
-	return price
-}
-
 func (p Pool) GetAddress() sdk.AccAddress {
 	return sdk.AccAddress{}
 }
@@ -75,128 +69,186 @@ func (p Pool) SpotPrice(ctx sdk.Context, baseAssetDenom string, quoteAssetDenom
 	return sdk.Dec{}, nil
 }
 
+type SwapState struct {
+	amountSpecifiedRemaining sdk.Dec // remaining amount of tokens that need to be bought by the pool
+	amountCalculated         sdk.Dec // amount out
+	sqrtPrice                sdk.Dec // new current price when swap is done
+	tick                     sdk.Int // new tick when swap is done
+}
+
 // this only works on a single directional trade, will implement bi directional trade in next milestone
-func (p Pool) CalcOutAmtGivenIn(ctx sdk.Context, tokenIn sdk.Coin, tokenOutDenom string, swapFee sdk.Dec) (tokenOut sdk.Coin, err error) {
+func (k Keeper) CalcOutAmtGivenIn(ctx sdk.Context, tokenIn sdk.Coin, tokenOutDenom string, swapFee sdk.Dec, minPrice, maxPrice sdk.Dec, poolId uint64) (newTokenIn, tokenOut sdk.Coin, err error) {
+	p := k.getPoolbyId(ctx, poolId)
 	asset0 := p.Token0
 	asset1 := p.Token1
+	tokenAmountInAfterFee := tokenIn.Amount.ToDec().Mul(sdk.OneDec().Sub(swapFee))
+
+	// get current sqrt price from pool
+	curSqrtPrice := p.CurrentSqrtPrice
+
+	// validation
 	if tokenIn.Denom != asset0 && tokenIn.Denom != asset1 {
-		return sdk.Coin{}, fmt.Errorf("tokenIn (%s) does not match any asset in pool", tokenIn.Denom)
+		return sdk.Coin{}, sdk.Coin{}, fmt.Errorf("tokenIn (%s) does not match any asset in pool", tokenIn.Denom)
 	}
 	if tokenOutDenom != asset0 && tokenOutDenom != asset1 {
-		return sdk.Coin{}, fmt.Errorf("tokenOutDenom (%s) does not match any asset in pool", tokenOutDenom)
+		return sdk.Coin{}, sdk.Coin{}, fmt.Errorf("tokenOutDenom (%s) does not match any asset in pool", tokenOutDenom)
 	}
 	if tokenIn.Denom == tokenOutDenom {
-		return sdk.Coin{}, fmt.Errorf("tokenIn (%s) cannot be the same as tokenOut (%s)", tokenIn.Denom, tokenOutDenom)
+		return sdk.Coin{}, sdk.Coin{}, fmt.Errorf("tokenIn (%s) cannot be the same as tokenOut (%s)", tokenIn.Denom, tokenOutDenom)
+	}
+	if minPrice.GTE(curSqrtPrice.Power(2)) {
+		return sdk.Coin{}, sdk.Coin{}, fmt.Errorf("minPrice (%s) must be less than current price (%s)", minPrice, curSqrtPrice.Power(2))
+	}
+	if maxPrice.LTE(curSqrtPrice.Power(2)) {
+		return sdk.Coin{}, sdk.Coin{}, fmt.Errorf("maxPrice (%s) must be greater than current price (%s)", maxPrice, curSqrtPrice.Power(2))
 	}
-	tokenAmountInAfterFee := tokenIn.Amount.ToDec().Mul(sdk.OneDec().Sub(swapFee))
 
-	// TODO: Replace with spot price
-	priceLower := sdk.NewDec(4500)
-	priceCur := sdk.NewDec(5000)
-	priceUpper := sdk.NewDec(5500)
+	// sqrtPrice of upper and lower user defined price range
+	sqrtPLowerTick, err := minPrice.ApproxSqrt()
+	if err != nil {
+		return sdk.Coin{}, sdk.Coin{}, fmt.Errorf("issue calculating square root of minPrice")
+	}
 
-	sqrtPLowerTick, _ := priceLower.ApproxSqrt()
-	sqrtPCurTick, _ := priceCur.ApproxSqrt()
-	sqrtPUpperTick, _ := priceUpper.ApproxSqrt()
+	sqrtPUpperTick, err := maxPrice.ApproxSqrt()
+	if err != nil {
+		return sdk.Coin{}, sdk.Coin{}, fmt.Errorf("issue calculating square root of maxPrice")
+	}
 
-	// TODO: Roman change out with query to pool to get this info
+	// TODO: How do we remove/generalize this? I am stumped.
+	// the following coins represent the virtual amounts in the current price bucket
 	amountETH := int64(1000000)
 	amountUSDC := int64(5000000000)
 
-	liq0 := liquidity0(amountETH, sqrtPCurTick, sqrtPUpperTick)
-	liq1 := liquidity1(amountUSDC, sqrtPCurTick, sqrtPLowerTick)
+	// find liquidity of assetA and assetB
+	liq0 := liquidity0(amountETH, curSqrtPrice, sqrtPUpperTick)
+	liq1 := liquidity1(amountUSDC, curSqrtPrice, sqrtPLowerTick)
 
+	// utilize the smaller liquidity between assetA and assetB when performing the swap calculation
 	liq := sdk.MinDec(liq0, liq1)
-	if tokenIn.Denom == asset1 {
-		priceDiff := tokenAmountInAfterFee.Quo(liq)
-		priceNext := sqrtPCurTick.Add(priceDiff)
-		// new amount in, will be needed later
-		//amountIn = calcAmount1(liq, priceNext, sqrtPCurTick)
-		amountOut := calcAmount0Delta(liq, priceNext, sqrtPCurTick)
-		return sdk.NewCoin(tokenOutDenom, amountOut.TruncateInt()), nil
-	} else if tokenIn.Denom == asset0 {
-		priceNextTop := liq.Mul(sqrtPCurTick)
-		priceNextBot := liq.Add(tokenAmountInAfterFee.Mul(sqrtPCurTick))
-		priceNext := priceNextTop.Quo(priceNextBot)
-		// new amount in, will be needed later
-		//amountIn = calcAmount1(liq, priceNext, sqrtPCurTick)
-		amountOut := calcAmount1Delta(liq, priceNext, sqrtPCurTick)
-		return sdk.NewCoin(tokenOutDenom, amountOut.TruncateInt()), nil
-	}
-	return sdk.Coin{}, fmt.Errorf("tokenIn (%s) does not match any asset in pool", tokenIn.Denom)
+
+	swapState := SwapState{
+		amountSpecifiedRemaining: tokenAmountInAfterFee,
+		amountCalculated:         sdk.ZeroDec(),
+		sqrtPrice:                curSqrtPrice,
+		tick:                     priceToTick(curSqrtPrice.Power(2)),
+	}
+
+	// TODO: This should be GT 0 but some instances have very small remainder
+	// need to look into fixing this
+	for swapState.amountSpecifiedRemaining.GT(sdk.NewDecWithPrec(1, 6)) {
+		lte := tokenIn.Denom == asset1
+		nextTick, _ := k.NextInitializedTick(ctx, poolId, swapState.tick.Int64(), lte)
+		// TODO: we can enable this error checking once we fix tick initialization
+		// if !ok {
+		// 	return sdk.Coin{}, sdk.Coin{}, fmt.Errorf("there are no more ticks initialized to fill the swap")
+		// }
+		nextSqrtPrice, err := k.tickToSqrtPrice(sdk.NewInt(nextTick))
+		if err != nil {
+			return sdk.Coin{}, sdk.Coin{}, fmt.Errorf("could not convert next tick (%v) to nextSqrtPrice", sdk.NewInt(nextTick))
+		}
+
+		sqrtPrice, amountIn, amountOut := computeSwapStep(
+			swapState.sqrtPrice,
+			nextSqrtPrice,
+			liq,
+			swapState.amountSpecifiedRemaining,
+			lte,
+		)
+		swapState.amountSpecifiedRemaining = swapState.amountSpecifiedRemaining.Sub(amountIn)
+		swapState.amountCalculated = swapState.amountCalculated.Add(amountOut)
+		swapState.tick = priceToTick(sqrtPrice.Power(2))
+	}
+
+	newTokenIn.Amount = tokenIn.Amount.Sub(swapState.amountSpecifiedRemaining.RoundInt())
+	return sdk.NewCoin(tokenIn.Denom, newTokenIn.Amount), sdk.NewCoin(tokenOutDenom, swapState.amountCalculated.RoundInt()), nil
 }
 
 func (p Pool) SwapInAmtGivenOut(ctx sdk.Context, tokenOut sdk.Coins, tokenInDenom string, swapFee sdk.Dec) (tokenIn sdk.Coin, err error) {
 	return sdk.Coin{}, nil
 }
 
-func (p Pool) CalcInAmtGivenOut(ctx sdk.Context, tokenOut sdk.Coin, tokenInDenom string, swapFee sdk.Dec) (tokenIn sdk.Coin, err error) {
+func (k Keeper) CalcInAmtGivenOut(ctx sdk.Context, tokenOut sdk.Coin, tokenInDenom string, swapFee sdk.Dec, minPrice, maxPrice sdk.Dec, poolId uint64) (tokenIn, newTokenOut sdk.Coin, err error) {
 	tokenOutAmt := tokenOut.Amount.ToDec()
+	p := k.getPoolbyId(ctx, poolId)
 	asset0 := p.Token0
 	asset1 := p.Token1
+
+	// get current sqrt price from pool
+	// curSqrtPrice := sdk.NewDecWithPrec(int64(p.CurrentSqrtPrice.Uint64()), 6)
+	curSqrtPrice := p.CurrentSqrtPrice
+
+	// validation
 	if tokenOut.Denom != asset0 && tokenOut.Denom != asset1 {
-		return sdk.Coin{}, fmt.Errorf("tokenOut denom (%s) does not match any asset in pool", tokenOut.Denom)
+		return sdk.Coin{}, sdk.Coin{}, fmt.Errorf("tokenOut denom (%s) does not match any asset in pool", tokenOut.Denom)
 	}
 	if tokenInDenom != asset0 && tokenInDenom != asset1 {
-		return sdk.Coin{}, fmt.Errorf("tokenInDenom (%s) does not match any asset in pool", tokenInDenom)
+		return sdk.Coin{}, sdk.Coin{}, fmt.Errorf("tokenInDenom (%s) does not match any asset in pool", tokenInDenom)
 	}
 	if tokenOut.Denom == tokenInDenom {
-		return sdk.Coin{}, fmt.Errorf("tokenOut (%s) cannot be the same as tokenIn (%s)", tokenOut.Denom, tokenInDenom)
+		return sdk.Coin{}, sdk.Coin{}, fmt.Errorf("tokenOut (%s) cannot be the same as tokenIn (%s)", tokenOut.Denom, tokenInDenom)
+	}
+	if minPrice.GTE(curSqrtPrice.Power(2)) {
+		return sdk.Coin{}, sdk.Coin{}, fmt.Errorf("minPrice (%s) must be less than current price (%s)", minPrice, curSqrtPrice.Power(2))
+	}
+	if maxPrice.LTE(curSqrtPrice.Power(2)) {
+		return sdk.Coin{}, sdk.Coin{}, fmt.Errorf("maxPrice (%s) must be greater than current price (%s)", maxPrice, curSqrtPrice.Power(2))
 	}
 
-	// TODO: Replace with spot price
-	priceLower := sdk.NewDec(4500)
-	priceCur := sdk.NewDec(5000)
-	priceUpper := sdk.NewDec(5500)
+	// sqrtPrice of upper and lower user defined price range
+	sqrtPLowerTick, err := minPrice.ApproxSqrt()
+	if err != nil {
+		return sdk.Coin{}, sdk.Coin{}, fmt.Errorf("issue calculating square root of minPrice")
+	}
 
-	sqrtPLowerTick, _ := priceLower.ApproxSqrt()
-	sqrtPCurTick, _ := priceCur.ApproxSqrt()
-	sqrtPUpperTick, _ := priceUpper.ApproxSqrt()
+	sqrtPUpperTick, err := maxPrice.ApproxSqrt()
+	if err != nil {
+		return sdk.Coin{}, sdk.Coin{}, fmt.Errorf("issue calculating square root of maxPrice")
+	}
 
-	// TODO: Roman change out with query to pool to get this info
+	// TODO: How do we remove/generalize this? I am stumped.
 	amountETH := int64(1000000)
 	amountUSDC := int64(5000000000)
 
-	liq0 := liquidity0(amountETH, sqrtPCurTick, sqrtPUpperTick)
-	liq1 := liquidity1(amountUSDC, sqrtPCurTick, sqrtPLowerTick)
+	// find liquidity of assetA and assetB
+	liq0 := liquidity0(amountETH, curSqrtPrice, sqrtPUpperTick)
+	liq1 := liquidity1(amountUSDC, curSqrtPrice, sqrtPLowerTick)
 
+	// utilize the smaller liquidity between assetA and assetB when performing the swap calculation
 	liq := sdk.MinDec(liq0, liq1)
 
-	if tokenOut.Denom == asset1 {
-		priceDiff := tokenOutAmt.Quo(liq)
-		priceNext := sqrtPCurTick.Add(priceDiff)
-
-		// new amount in, will be needed later
-		// amountIn = calcAmount1(liq, priceNext, sqrtPCurTick)
-		amountIn := calcAmount0Delta(liq, priceNext, sqrtPCurTick)
-		// fee logic
-		amountIn = amountIn.Quo(sdk.OneDec().Sub(swapFee))
-		return sdk.NewCoin(tokenInDenom, amountIn.RoundInt()), nil
-	} else if tokenOut.Denom == asset0 {
-		priceNextTop := liq.Mul(sqrtPCurTick)
-		priceNextBot := liq.Add(tokenOutAmt.Mul(sqrtPCurTick))
-		priceNext := priceNextTop.Quo(priceNextBot)
-
-		// new amount in, will be needed later
-		// amountIn = calcAmount1(liq, priceNext, sqrtPCurTick)
-		amountIn := calcAmount1Delta(liq, priceNext, sqrtPCurTick)
-		// fee logic
-		amountIn = amountIn.Quo(sdk.OneDec().Sub(swapFee))
-		return sdk.NewCoin(tokenInDenom, amountIn.RoundInt()), nil
-	}
-	return sdk.Coin{}, fmt.Errorf("tokenOut (%s) does not match any asset in pool", tokenOut.Denom)
-}
-
-func (p *Pool) orderInitialPoolDenoms(denom0, denom1 string) error {
-	if denom0 == denom1 {
-		return fmt.Errorf("cannot have the same asset in a single pool")
-	}
-	if denom0 > denom1 {
-		denom1, denom0 = denom0, denom1
+	swapState := SwapState{
+		amountSpecifiedRemaining: tokenOutAmt,
+		amountCalculated:         sdk.ZeroDec(),
+		sqrtPrice:                curSqrtPrice,
+		tick:                     priceToTick(curSqrtPrice.Power(2)),
 	}
 
-	p.Token0 = denom0
-	p.Token1 = denom1
-
-	return nil
+	// TODO: This should be GT 0 but some instances have very small remainder
+	// need to look into fixing this
+	for swapState.amountSpecifiedRemaining.GT(sdk.NewDecWithPrec(1, 6)) {
+		lte := tokenOut.Denom == asset1
+		nextTick, _ := k.NextInitializedTick(ctx, poolId, swapState.tick.Int64(), lte)
+		// TODO: we can enable this error checking once we fix tick initialization
+		// if !ok {
+		// 	return sdk.Coin{}, sdk.Coin{}, fmt.Errorf("there are no more ticks initialized to fill the swap")
+		// }
+		nextSqrtPrice, err := k.tickToSqrtPrice(sdk.NewInt(nextTick))
+		if err != nil {
+			return sdk.Coin{}, sdk.Coin{}, err
+		}
+
+		// TODO: In and out get flipped based on if we are calculating for in or out, need to fix this
+		sqrtPrice, amountIn, amountOut := computeSwapStep(
+			swapState.sqrtPrice,
+			nextSqrtPrice,
+			liq,
+			swapState.amountSpecifiedRemaining,
+			lte,
+		)
+
+		swapState.amountSpecifiedRemaining = swapState.amountSpecifiedRemaining.Sub(amountIn)
+		swapState.amountCalculated = swapState.amountCalculated.Add(amountOut.Quo(sdk.OneDec().Sub(swapFee)))
+		swapState.tick = priceToTick(sqrtPrice.Power(2))
+	}
+	return sdk.NewCoin(tokenInDenom, swapState.amountCalculated.RoundInt()), sdk.NewCoin(tokenOut.Denom, tokenOut.Amount), nil
 }
diff --git a/x/concentrated-liquidity/tick.go b/x/concentrated-liquidity/tick.go
index 65d536678..5b38be7b4 100644
--- a/x/concentrated-liquidity/tick.go
+++ b/x/concentrated-liquidity/tick.go
@@ -12,13 +12,13 @@ import (
 	types "github.com/osmosis-labs/osmosis/v12/x/concentrated-liquidity/types"
 )
 
-func (k Keeper) getSqrtRatioAtTick(tickIndex int64) (sdk.Dec, error) {
-	sqrtRatio, err := sdk.NewDecWithPrec(10001, 4).Power(uint64(tickIndex)).ApproxSqrt()
+func (k Keeper) tickToSqrtPrice(tickIndex sdk.Int) (sdk.Dec, error) {
+	price, err := sdk.NewDecWithPrec(10001, 4).Power(tickIndex.Uint64()).ApproxSqrt()
 	if err != nil {
-		return sdk.Dec{}, nil
+		return sdk.Dec{}, err
 	}
 
-	return sqrtRatio, nil
+	return price, nil
 }
 
 // TODO: implement this
diff --git a/x/concentrated-liquidity/types/cl.go b/x/concentrated-liquidity/types/cl.go
new file mode 100644
index 000000000..1c38958ec
--- /dev/null
+++ b/x/concentrated-liquidity/types/cl.go
@@ -0,0 +1,14 @@
+package types
+
+import fmt "fmt"
+
+func OrderInitialPoolDenoms(denom0, denom1 string) (string, string, error) {
+	if denom0 == denom1 {
+		return "", "", fmt.Errorf("cannot have the same asset in a single pool")
+	}
+	if denom0 > denom1 {
+		denom1, denom0 = denom0, denom1
+	}
+
+	return denom0, denom1, nil
+}


Test patch:
diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml
index b5ade8be7..0108408cf 100644
--- a/.github/workflows/test.yml
+++ b/.github/workflows/test.yml
@@ -7,6 +7,7 @@ on:
   push:
     branches:
       - "main"
+      - "concentrated-liquidity-main"
       - "v[0-9]**"
   workflow_dispatch:
 
@@ -124,3 +125,4 @@ jobs:
       -
         name: Test e2e and Upgrade
         run: make test-e2e-ci
+        
diff --git a/osmomath/decimal_test.go b/osmomath/decimal_test.go
index 92b886d1d..cabf1409c 100644
--- a/osmomath/decimal_test.go
+++ b/osmomath/decimal_test.go
@@ -204,8 +204,8 @@ func (s *decimalTestSuite) TestBigDecFromSdkDec() {
 
 func (s *decimalTestSuite) TestBigDecFromSdkDecSlice() {
 	tests := []struct {
-		d    []sdk.Dec
-		want []BigDec
+		d        []sdk.Dec
+		want     []BigDec
 		expPanic bool
 	}{
 		{[]sdk.Dec{sdk.MustNewDecFromStr("0.000000000000000000")}, []BigDec{NewBigDec(0)}, false},
@@ -654,6 +654,7 @@ func BenchmarkMarshalTo(b *testing.B) {
 }
 
 func (s *decimalTestSuite) TestLog2() {
+	var expectedErrTolerance = MustNewDecFromStr("0.000000000000000000000000000000000100")
 
 	tests := map[string]struct {
 		initialValue BigDec
@@ -661,11 +662,29 @@ func (s *decimalTestSuite) TestLog2() {
 
 		expectedPanic bool
 	}{
-		"log_2{0.99}; not supported; panic": {
-			initialValue: NewDecWithPrec(99, 2),
-
+		"log_2{-1}; invalid; panic": {
+			initialValue:  OneDec().Neg(),
+			expectedPanic: true,
+		},
+		"log_2{0}; invalid; panic": {
+			initialValue:  ZeroDec(),
 			expectedPanic: true,
 		},
+		"log_2{0.001} = -9.965784284662087043610958288468170528": {
+			initialValue: MustNewDecFromStr("0.001"),
+			// From: https://www.wolframalpha.com/input?i=log+base+2+of+0.999912345+with+33+digits
+			expected: MustNewDecFromStr("-9.965784284662087043610958288468170528"),
+		},
+		"log_2{0.56171821941421412902170941} = -0.832081497183140708984033250637831402": {
+			initialValue: MustNewDecFromStr("0.56171821941421412902170941"),
+			// From: https://www.wolframalpha.com/input?i=log+base+2+of+0.56171821941421412902170941+with+36+digits
+			expected: MustNewDecFromStr("-0.832081497183140708984033250637831402"),
+		},
+		"log_2{0.999912345} = -0.000126464976533858080645902722235833": {
+			initialValue: MustNewDecFromStr("0.999912345"),
+			// From: https://www.wolframalpha.com/input?i=log+base+2+of+0.999912345+with+37+digits
+			expected: MustNewDecFromStr("-0.000126464976533858080645902722235833"),
+		},
 		"log_2{1} = 0": {
 			initialValue: NewBigDec(1),
 			expected:     NewBigDec(0),
@@ -674,39 +693,48 @@ func (s *decimalTestSuite) TestLog2() {
 			initialValue: NewBigDec(2),
 			expected:     NewBigDec(1),
 		},
+		"log_2{7} = 2.807354922057604107441969317231830809": {
+			initialValue: NewBigDec(7),
+			// From: https://www.wolframalpha.com/input?i=log+base+2+of+7+37+digits
+			expected: MustNewDecFromStr("2.807354922057604107441969317231830809"),
+		},
 		"log_2{512} = 9": {
 			initialValue: NewBigDec(512),
 			expected:     NewBigDec(9),
 		},
-		"log_2{600} = 9": {
+		"log_2{580} = 9.179909090014934468590092754117374938": {
 			initialValue: NewBigDec(580),
-			// TODO: true value is: 9.179909090014934468590092754117374938
-			// Need better lookup table.
-			expected: MustNewDecFromStr("9.137503523749934908329043617236402782"),
+			// From: https://www.wolframalpha.com/input?i=log+base+2+of+600+37+digits
+			expected: MustNewDecFromStr("9.179909090014934468590092754117374938"),
 		},
 		"log_2{1024} = 10": {
 			initialValue: NewBigDec(1024),
 			expected:     NewBigDec(10),
 		},
-		"log_2{1024.987654321} = 10": {
+		"log_2{1024.987654321} = 10.001390817654141324352719749259888355": {
 			initialValue: NewDecWithPrec(1024987654321, 9),
-			// TODO: true value is: 10.001390817654141324352719749259888355
-			// Need better lookup table
-			expected: MustNewDecFromStr("10.000000000000000000000000000000000000"),
+			// From: https://www.wolframalpha.com/input?i=log+base+2+of+1024.987654321+38+digits
+			expected: MustNewDecFromStr("10.001390817654141324352719749259888355"),
 		},
 		"log_2{912648174127941279170121098210.92821920190204131121} = 99.525973560175362367047484597337715868": {
 			initialValue: MustNewDecFromStr("912648174127941279170121098210.92821920190204131121"),
-			// TODO: true value is: 99.525973560175362367047484597337715868
-			// Need better lookup table
-			expected: MustNewDecFromStr("99.485426827170241759571649887742440632"),
+			// From: https://www.wolframalpha.com/input?i=log+base+2+of+912648174127941279170121098210.92821920190204131121+38+digits
+			expected: MustNewDecFromStr("99.525973560175362367047484597337715868"),
 		},
 	}
 
 	for name, tc := range tests {
 		s.Run(name, func() {
 			osmoassert.ConditionalPanic(s.T(), tc.expectedPanic, func() {
-				res := tc.initialValue.ApproxLog2()
-				s.Require().Equal(tc.expected, res)
+				// Create a copy to test that the original was not modified.
+				// That is, that LogbBase2() is non-mutative.
+				initialCopy := ZeroDec()
+				initialCopy.i.Set(tc.initialValue.i)
+
+				// system under test.
+				res := tc.initialValue.LogBase2()
+				require.True(DecApproxEq(s.T(), tc.expected, res, expectedErrTolerance))
+				require.Equal(s.T(), initialCopy, tc.initialValue)
 			})
 		})
 	}
diff --git a/osmomath/log2_bench_test.go b/osmomath/log2_bench_test.go
index 1a723be16..9b4ab3c33 100644
--- a/osmomath/log2_bench_test.go
+++ b/osmomath/log2_bench_test.go
@@ -1,34 +1,24 @@
 package osmomath
 
 import (
+	"math/rand"
 	"testing"
 )
 
 func BenchmarkLog2(b *testing.B) {
-	tests := []struct {
-		value BigDec
-	}{
-		// TODO: Choose selection here more robustly
-		{
-			value: MustNewDecFromStr("1.2"),
-		},
-		{
-			value: MustNewDecFromStr("1.234"),
-		},
-		{
-			value: MustNewDecFromStr("1024"),
-		},
-		{
-			value: NewBigDec(2048 * 2048 * 2048 * 2048 * 2048),
-		},
-		{
-			value: MustNewDecFromStr("999999999999999999999999999999999999999999999999999999.9122181273612911"),
-		},
+	tests := []BigDec{
+		MustNewDecFromStr("1.2"),
+		MustNewDecFromStr("1.234"),
+		MustNewDecFromStr("1024"),
+		NewBigDec(2048 * 2048 * 2048 * 2048 * 2048),
+		MustNewDecFromStr("999999999999999999999999999999999999999999999999999999.9122181273612911"),
+		MustNewDecFromStr("0.563289239121902491248219047129047129"),
 	}
 
 	for i := 0; i < b.N; i++ {
-		for _, test := range tests {
-			test.value.ApproxLog2()
-		}
+		b.StopTimer()
+		test := tests[rand.Int63n(int64(len(tests)))]
+		b.StartTimer()
+		_ = test.LogBase2()
 	}
 }
diff --git a/osmomath/rounding_direction_test.go b/osmomath/rounding_direction_test.go
index 8668c84c6..3fac4b62c 100644
--- a/osmomath/rounding_direction_test.go
+++ b/osmomath/rounding_direction_test.go
@@ -42,7 +42,6 @@ func TestDivIntByU64ToBigDec(t *testing.T) {
 	addTCForAllRoundingModes("odd divided by 2", sdk.NewInt(5), 2, NewDecWithPrec(25, 1))
 
 	for name, tt := range tests {
-		fmt.Println("start")
 		t.Run(name, func(t *testing.T) {
 			got, err := DivIntByU64ToBigDec(tt.i, tt.u, tt.round)
 			require.Equal(t, tt.want, got)
diff --git a/x/concentrated-liquidity/export_test.go b/x/concentrated-liquidity/export_test.go
index e7b83d55a..f52e111dd 100644
--- a/x/concentrated-liquidity/export_test.go
+++ b/x/concentrated-liquidity/export_test.go
@@ -1,6 +1,10 @@
 package concentrated_liquidity
 
+import (
+	cltypes "github.com/osmosis-labs/osmosis/v12/x/concentrated-liquidity/types"
+)
+
 // OrderInitialPoolDenoms sets the pool denoms of a cl pool
-func (p *Pool) OrderInitialPoolDenoms(denom0, denom1 string) error {
-	return p.orderInitialPoolDenoms(denom0, denom1)
+func OrderInitialPoolDenoms(denom0, denom1 string) (string, string, error) {
+	return cltypes.OrderInitialPoolDenoms(denom0, denom1)
 }
diff --git a/x/concentrated-liquidity/lp_test.go b/x/concentrated-liquidity/lp_test.go
index e8c5c4c00..40938cb3a 100644
--- a/x/concentrated-liquidity/lp_test.go
+++ b/x/concentrated-liquidity/lp_test.go
@@ -9,25 +9,29 @@ func (s *KeeperTestSuite) TestMint() {
 	// current tick: 85176
 	// lower tick: 84222
 	// upper tick: 86129
-	// liquidity(token in):1517882343751509868544
-	// current sqrt price: 5602277097478614198912276234240
-	// denom0: uosmo
+	// liquidity(token in):1517882323
+	// current sqrt price: 70710678
+	// denom0: eth
 	// denom1: usdc
 	poolId := uint64(1)
 	currentTick := sdk.NewInt(85176)
 	lowerTick := int64(84222)
 	upperTick := int64(86129)
-	liquidity, ok := sdk.NewIntFromString("1517882343751509868544")
-	s.Require().True(ok)
-	currentSqrtP, ok := sdk.NewIntFromString("5602277097478614198912276234240")
-	s.Require().True(ok)
-	denom0 := "uosmo"
+	liquidity, err := sdk.NewDecFromStr("1517.882323")
+	s.Require().NoError(err)
+	// currentSqrtP, ok := sdk.NewIntFromString("70710678")
+	currentSqrtP, err := sdk.NewDecFromStr("70.710678")
+	s.Require().NoError(err)
+	denom0 := "eth"
 	denom1 := "usdc"
 
 	s.SetupTest()
 
 	s.App.ConcentratedLiquidityKeeper.CreateNewConcentratedLiquidityPool(s.Ctx, poolId, denom0, denom1, currentSqrtP, currentTick)
 
-	_, _, err := s.App.ConcentratedLiquidityKeeper.Mint(s.Ctx, poolId, s.TestAccs[0], liquidity, lowerTick, upperTick)
+	asset0, asset1, err := s.App.ConcentratedLiquidityKeeper.Mint(s.Ctx, poolId, s.TestAccs[0], liquidity, lowerTick, upperTick)
 	s.Require().NoError(err)
+
+	s.Require().Equal(sdk.NewInt(1), asset0)
+	s.Require().Equal(sdk.NewInt(5000), asset1)
 }
diff --git a/x/concentrated-liquidity/pool_test.go b/x/concentrated-liquidity/pool_test.go
index 861aee730..1d30c495f 100644
--- a/x/concentrated-liquidity/pool_test.go
+++ b/x/concentrated-liquidity/pool_test.go
@@ -1,94 +1,102 @@
 package concentrated_liquidity_test
 
 import (
-	fmt "fmt"
-
 	sdk "github.com/cosmos/cosmos-sdk/types"
+
+	cltypes "github.com/osmosis-labs/osmosis/v12/x/concentrated-liquidity/types"
 )
 
 func (s *KeeperTestSuite) TestCalcOutAmtGivenIn() {
 	ctx := s.Ctx
-	pool, err := s.App.ConcentratedLiquidityKeeper.CreateNewConcentratedLiquidityPool(s.Ctx, 1, "eth", "usdc", sdk.NewInt(0), sdk.NewInt(0))
+	pool, err := s.App.ConcentratedLiquidityKeeper.CreateNewConcentratedLiquidityPool(ctx, 1, "eth", "usdc", sdk.MustNewDecFromStr("70.710678"), sdk.NewInt(85176))
 	s.Require().NoError(err)
 
 	// test asset a to b logic
 	tokenIn := sdk.NewCoin("eth", sdk.NewInt(133700))
 	tokenOutDenom := "usdc"
 	swapFee := sdk.NewDec(0)
+	minPrice := sdk.NewDec(4500)
+	maxPrice := sdk.NewDec(5500)
 
-	amountOut, err := pool.CalcOutAmtGivenIn(ctx, tokenIn, tokenOutDenom, swapFee)
+	_, amountOut, err := s.App.ConcentratedLiquidityKeeper.CalcOutAmtGivenIn(ctx, tokenIn, tokenOutDenom, swapFee, minPrice, maxPrice, pool.Id)
 	s.Require().NoError(err)
-	s.Require().Equal(sdk.NewDec(663944647).String(), amountOut.Amount.ToDec().String())
+	s.Require().Equal(sdk.NewDec(666975610).String(), amountOut.Amount.ToDec().String())
 
 	// test asset b to a logic
 	tokenIn = sdk.NewCoin("usdc", sdk.NewInt(4199999999))
 	tokenOutDenom = "eth"
 	swapFee = sdk.NewDec(0)
 
-	amountOut, err = pool.CalcOutAmtGivenIn(ctx, tokenIn, tokenOutDenom, swapFee)
+	_, amountOut, err = s.App.ConcentratedLiquidityKeeper.CalcOutAmtGivenIn(ctx, tokenIn, tokenOutDenom, swapFee, minPrice, maxPrice, pool.Id)
 	s.Require().NoError(err)
 	s.Require().Equal(sdk.NewDec(805287), amountOut.Amount.ToDec())
 
+	// test asset b to a logic
+	tokenIn = sdk.NewCoin("usdc", sdk.NewInt(42000000))
+	tokenOutDenom = "eth"
+	swapFee = sdk.NewDec(0)
+
+	_, amountOut, err = s.App.ConcentratedLiquidityKeeper.CalcOutAmtGivenIn(ctx, tokenIn, tokenOutDenom, swapFee, minPrice, maxPrice, pool.Id)
+	s.Require().NoError(err)
+	s.Require().Equal(sdk.NewDec(8396), amountOut.Amount.ToDec())
+
 	// test with swap fee
 	tokenIn = sdk.NewCoin("usdc", sdk.NewInt(4199999999))
 	tokenOutDenom = "eth"
 	swapFee = sdk.NewDecWithPrec(2, 2)
 
-	amountOut, err = pool.CalcOutAmtGivenIn(ctx, tokenIn, tokenOutDenom, swapFee)
+	_, amountOut, err = s.App.ConcentratedLiquidityKeeper.CalcOutAmtGivenIn(ctx, tokenIn, tokenOutDenom, swapFee, minPrice, maxPrice, pool.Id)
 	s.Require().NoError(err)
 	s.Require().Equal(sdk.NewDec(789834), amountOut.Amount.ToDec())
 }
 
 func (s *KeeperTestSuite) TestCalcInAmtGivenOut() {
 	ctx := s.Ctx
-	fmt.Println("===0")
-	pool, err := s.App.ConcentratedLiquidityKeeper.CreateNewConcentratedLiquidityPool(s.Ctx, 1, "eth", "usdc", sdk.NewInt(0), sdk.NewInt(0))
+	pool, err := s.App.ConcentratedLiquidityKeeper.CreateNewConcentratedLiquidityPool(s.Ctx, 1, "eth", "usdc", sdk.MustNewDecFromStr("70.710678"), sdk.NewInt(85176))
 	s.Require().NoError(err)
+
 	// test asset a to b logic
-	tokensOut := sdk.NewCoin("usdc", sdk.NewInt(4199999999))
+	tokenOut := sdk.NewCoin("usdc", sdk.NewInt(4199999999))
 	tokenInDenom := "eth"
 	swapFee := sdk.NewDec(0)
+	minPrice := sdk.NewDec(4500)
+	maxPrice := sdk.NewDec(5500)
 
-	amountIn, err := pool.CalcInAmtGivenOut(ctx, tokensOut, tokenInDenom, swapFee)
+	amountIn, _, err := s.App.ConcentratedLiquidityKeeper.CalcInAmtGivenOut(ctx, tokenOut, tokenInDenom, swapFee, minPrice, maxPrice, pool.Id)
 	s.Require().NoError(err)
 	s.Require().Equal(sdk.NewDec(805287), amountIn.Amount.ToDec())
 
 	// test asset b to a logic
-	tokensOut = sdk.NewCoin("eth", sdk.NewInt(133700))
+	tokenOut = sdk.NewCoin("eth", sdk.NewInt(133700))
 	tokenInDenom = "usdc"
 	swapFee = sdk.NewDec(0)
 
-	amountIn, err = pool.CalcInAmtGivenOut(ctx, tokensOut, tokenInDenom, swapFee)
+	amountIn, _, err = s.App.ConcentratedLiquidityKeeper.CalcInAmtGivenOut(ctx, tokenOut, tokenInDenom, swapFee, minPrice, maxPrice, pool.Id)
 	s.Require().NoError(err)
-	s.Require().Equal(sdk.NewDec(663944647), amountIn.Amount.ToDec())
+	s.Require().Equal(sdk.NewDec(666975610), amountIn.Amount.ToDec())
 
 	// test asset a to b logic
-	tokensOut = sdk.NewCoin("usdc", sdk.NewInt(4199999999))
+	tokenOut = sdk.NewCoin("usdc", sdk.NewInt(4199999999))
 	tokenInDenom = "eth"
 	swapFee = sdk.NewDecWithPrec(2, 2)
 
-	amountIn, err = pool.CalcInAmtGivenOut(ctx, tokensOut, tokenInDenom, swapFee)
+	amountIn, _, err = s.App.ConcentratedLiquidityKeeper.CalcInAmtGivenOut(ctx, tokenOut, tokenInDenom, swapFee, minPrice, maxPrice, pool.Id)
 	s.Require().NoError(err)
 	s.Require().Equal(sdk.NewDec(821722), amountIn.Amount.ToDec())
 }
 
 func (s *KeeperTestSuite) TestOrderInitialPoolDenoms() {
-	pool, err := s.App.ConcentratedLiquidityKeeper.CreateNewConcentratedLiquidityPool(s.Ctx, 1, "eth", "usdc", sdk.NewInt(0), sdk.NewInt(0))
-	s.Require().NoError(err)
-	s.Require().Equal(pool.Token0, "eth")
-	s.Require().Equal(pool.Token1, "usdc")
-
-	err = pool.OrderInitialPoolDenoms("axel", "osmo")
+	denom0, denom1, err := cltypes.OrderInitialPoolDenoms("axel", "osmo")
 	s.Require().NoError(err)
-	s.Require().Equal(pool.Token0, "axel")
-	s.Require().Equal(pool.Token1, "osmo")
+	s.Require().Equal(denom0, "axel")
+	s.Require().Equal(denom1, "osmo")
 
-	err = pool.OrderInitialPoolDenoms("usdc", "eth")
+	denom0, denom1, err = cltypes.OrderInitialPoolDenoms("usdc", "eth")
 	s.Require().NoError(err)
-	s.Require().Equal(pool.Token0, "eth")
-	s.Require().Equal(pool.Token1, "usdc")
+	s.Require().Equal(denom0, "eth")
+	s.Require().Equal(denom1, "usdc")
 
-	err = pool.OrderInitialPoolDenoms("usdc", "usdc")
+	denom0, denom1, err = cltypes.OrderInitialPoolDenoms("usdc", "usdc")
 	s.Require().Error(err)
 
 }