Repository: osmosis-labs/osmosis
Pull request #3057 (2022-10-19 20:14:24)

Add basic pool state, Make outlines for JoinPool
<!-- < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < ☺
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!
☺ > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > >  -->
This PR includes
- adding basic pool state( this can change in the future as we're going through development)
- Adding store keys and getters, setters for the store
- Utilizing them for structuring join pool


Patch:
diff --git a/osmomath/decimal.go b/osmomath/decimal.go
index 265f6ada0..761238fd5 100644
--- a/osmomath/decimal.go
+++ b/osmomath/decimal.go
@@ -4,6 +4,7 @@ import (
 	"encoding/json"
 	"errors"
 	"fmt"
+	"math"
 	"math/big"
 	"strconv"
 	"strings"
@@ -39,6 +40,8 @@ var (
 	zeroInt              = big.NewInt(0)
 	oneInt               = big.NewInt(1)
 	tenInt               = big.NewInt(10)
+
+	log2LookupTable map[uint16]BigDec
 )
 
 // Decimal errors
@@ -54,6 +57,28 @@ func init() {
 	for i := 0; i <= Precision; i++ {
 		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"),
+	}
 }
 
 func precisionInt() *big.Int {
@@ -211,7 +236,8 @@ func (d BigDec) GTE(d2 BigDec) bool   { return (d.i).Cmp(d2.i) >= 0 }          /
 func (d BigDec) LT(d2 BigDec) bool    { return (d.i).Cmp(d2.i) < 0 }           // less than
 func (d BigDec) LTE(d2 BigDec) bool   { return (d.i).Cmp(d2.i) <= 0 }          // less than or equal
 func (d BigDec) Neg() BigDec          { return BigDec{new(big.Int).Neg(d.i)} } // reverse the decimal sign
-func (d BigDec) Abs() BigDec          { return BigDec{new(big.Int).Abs(d.i)} } // absolute value
+// nolint: stylecheck
+func (d BigDec) Abs() BigDec { return BigDec{new(big.Int).Abs(d.i)} } // absolute value
 
 // BigInt returns a copy of the underlying big.Int.
 func (d BigDec) BigInt() *big.Int {
@@ -856,3 +882,55 @@ func DecApproxEq(t *testing.T, d1 BigDec, d2 BigDec, tol BigDec) (*testing.T, bo
 	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()
 }
+
+// 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))
+	}
+
+	// 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)
+	}
+	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))
+	}
+
+	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)
+}
diff --git a/proto/osmosis/concentrated-liquidity/concentratedPool.proto b/proto/osmosis/concentrated-liquidity/concentratedPool.proto
index 1737ecb1f..6410853cb 100644
--- a/proto/osmosis/concentrated-liquidity/concentratedPool.proto
+++ b/proto/osmosis/concentrated-liquidity/concentratedPool.proto
@@ -17,4 +17,43 @@ message Pool {
 
   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
+  ];
+
+  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
+  ];
+  string current_tick = 7 [
+    (gogoproto.customtype) = "github.com/cosmos/cosmos-sdk/types.Int",
+    (gogoproto.moretags) = "yaml:\"current_tick\"",
+    (gogoproto.nullable) = false
+  ];
+}
+
+message TickInfo {
+  bool initialized = 1;
+  // sum of all non-normalized pool weights
+  string liquidity = 2 [
+    (gogoproto.customtype) = "github.com/cosmos/cosmos-sdk/types.Int",
+    (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
+  ];
 }
diff --git a/x/concentrated-liquidity/concentratedPool.pb.go b/x/concentrated-liquidity/concentratedPool.pb.go
index ef229427f..a7dd06512 100644
--- a/x/concentrated-liquidity/concentratedPool.pb.go
+++ b/x/concentrated-liquidity/concentratedPool.pb.go
@@ -11,6 +11,7 @@ package concentrated_liquidity
 import (
 	fmt "fmt"
 	_ "github.com/cosmos/cosmos-proto"
+	github_com_cosmos_cosmos_sdk_types "github.com/cosmos/cosmos-sdk/types"
 	_ "github.com/gogo/protobuf/gogoproto"
 	proto "github.com/gogo/protobuf/proto"
 	io "io"
@@ -32,6 +33,12 @@ const _ = proto.GoGoProtoPackageIsVersion3 // please upgrade the proto package
 type Pool struct {
 	Address string `protobuf:"bytes,1,opt,name=address,proto3" json:"address,omitempty" yaml:"address"`
 	Id      uint64 `protobuf:"varint,2,opt,name=id,proto3" json:"id,omitempty"`
+	// Amount of total liquidity
+	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"`
+	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"`
 }
 
 func (m *Pool) Reset()      { *m = Pool{} }
@@ -66,8 +73,93 @@ func (m *Pool) XXX_DiscardUnknown() {
 
 var xxx_messageInfo_Pool proto.InternalMessageInfo
 
+type TickInfo struct {
+	Initialized bool `protobuf:"varint,1,opt,name=initialized,proto3" json:"initialized,omitempty"`
+	// sum of all non-normalized pool weights
+	Liquidity github_com_cosmos_cosmos_sdk_types.Int `protobuf:"bytes,2,opt,name=liquidity,proto3,customtype=github.com/cosmos/cosmos-sdk/types.Int" json:"liquidity" yaml:"liquidity"`
+}
+
+func (m *TickInfo) Reset()         { *m = TickInfo{} }
+func (m *TickInfo) String() string { return proto.CompactTextString(m) }
+func (*TickInfo) ProtoMessage()    {}
+func (*TickInfo) Descriptor() ([]byte, []int) {
+	return fileDescriptor_b144264ce94bcf63, []int{1}
+}
+func (m *TickInfo) XXX_Unmarshal(b []byte) error {
+	return m.Unmarshal(b)
+}
+func (m *TickInfo) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) {
+	if deterministic {
+		return xxx_messageInfo_TickInfo.Marshal(b, m, deterministic)
+	} else {
+		b = b[:cap(b)]
+		n, err := m.MarshalToSizedBuffer(b)
+		if err != nil {
+			return nil, err
+		}
+		return b[:n], nil
+	}
+}
+func (m *TickInfo) XXX_Merge(src proto.Message) {
+	xxx_messageInfo_TickInfo.Merge(m, src)
+}
+func (m *TickInfo) XXX_Size() int {
+	return m.Size()
+}
+func (m *TickInfo) XXX_DiscardUnknown() {
+	xxx_messageInfo_TickInfo.DiscardUnknown(m)
+}
+
+var xxx_messageInfo_TickInfo proto.InternalMessageInfo
+
+func (m *TickInfo) GetInitialized() bool {
+	if m != nil {
+		return m.Initialized
+	}
+	return false
+}
+
+type Position struct {
+	Liquidity github_com_cosmos_cosmos_sdk_types.Int `protobuf:"bytes,1,opt,name=liquidity,proto3,customtype=github.com/cosmos/cosmos-sdk/types.Int" json:"liquidity" yaml:"liquidity"`
+}
+
+func (m *Position) Reset()         { *m = Position{} }
+func (m *Position) String() string { return proto.CompactTextString(m) }
+func (*Position) ProtoMessage()    {}
+func (*Position) Descriptor() ([]byte, []int) {
+	return fileDescriptor_b144264ce94bcf63, []int{2}
+}
+func (m *Position) XXX_Unmarshal(b []byte) error {
+	return m.Unmarshal(b)
+}
+func (m *Position) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) {
+	if deterministic {
+		return xxx_messageInfo_Position.Marshal(b, m, deterministic)
+	} else {
+		b = b[:cap(b)]
+		n, err := m.MarshalToSizedBuffer(b)
+		if err != nil {
+			return nil, err
+		}
+		return b[:n], nil
+	}
+}
+func (m *Position) XXX_Merge(src proto.Message) {
+	xxx_messageInfo_Position.Merge(m, src)
+}
+func (m *Position) XXX_Size() int {
+	return m.Size()
+}
+func (m *Position) XXX_DiscardUnknown() {
+	xxx_messageInfo_Position.DiscardUnknown(m)
+}
+
+var xxx_messageInfo_Position proto.InternalMessageInfo
+
 func init() {
 	proto.RegisterType((*Pool)(nil), "osmosis.concentratedliquidity.v1beta1.Pool")
+	proto.RegisterType((*TickInfo)(nil), "osmosis.concentratedliquidity.v1beta1.TickInfo")
+	proto.RegisterType((*Position)(nil), "osmosis.concentratedliquidity.v1beta1.Position")
 }
 
 func init() {
@@ -75,23 +167,36 @@ func init() {
 }
 
 var fileDescriptor_b144264ce94bcf63 = []byte{
-	// 248 bytes of a gzipped FileDescriptorProto
-	0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xe2, 0x32, 0xcd, 0x2f, 0xce, 0xcd,
-	0x2f, 0xce, 0x2c, 0xd6, 0x4f, 0xce, 0xcf, 0x4b, 0x4e, 0xcd, 0x2b, 0x29, 0x4a, 0x2c, 0x49, 0x4d,
-	0xd1, 0xcd, 0xc9, 0x2c, 0x2c, 0xcd, 0x4c, 0xc9, 0x2c, 0xa9, 0x44, 0x11, 0x0e, 0xc8, 0xcf, 0xcf,
-	0xd1, 0x2b, 0x28, 0xca, 0x2f, 0xc9, 0x17, 0x52, 0x85, 0x6a, 0xd3, 0x43, 0x96, 0x87, 0xeb, 0xd2,
-	0x2b, 0x33, 0x4c, 0x4a, 0x2d, 0x49, 0x34, 0x94, 0x92, 0x4c, 0x06, 0xab, 0x8b, 0x07, 0x6b, 0xd2,
-	0x87, 0x70, 0x20, 0x26, 0x48, 0x89, 0xa4, 0xe7, 0xa7, 0xe7, 0x43, 0xc4, 0x41, 0x2c, 0x88, 0xa8,
-	0x52, 0x38, 0x17, 0x0b, 0xc8, 0x16, 0x21, 0x1d, 0x2e, 0xf6, 0xc4, 0x94, 0x94, 0xa2, 0xd4, 0xe2,
-	0x62, 0x09, 0x46, 0x05, 0x46, 0x0d, 0x4e, 0x27, 0xa1, 0x4f, 0xf7, 0xe4, 0xf9, 0x2a, 0x13, 0x73,
-	0x73, 0xac, 0x94, 0xa0, 0x12, 0x4a, 0x41, 0x30, 0x25, 0x42, 0x7c, 0x5c, 0x4c, 0x99, 0x29, 0x12,
-	0x4c, 0x0a, 0x8c, 0x1a, 0x2c, 0x41, 0x4c, 0x99, 0x29, 0x56, 0x82, 0x1d, 0x0b, 0xe4, 0x19, 0x66,
-	0x2c, 0x90, 0x67, 0x38, 0xb5, 0x45, 0x97, 0x15, 0x64, 0x9e, 0xa7, 0x53, 0xd8, 0x89, 0x47, 0x72,
-	0x8c, 0x17, 0x1e, 0xc9, 0x31, 0x3e, 0x78, 0x24, 0xc7, 0x38, 0xe1, 0xb1, 0x1c, 0xc3, 0x85, 0xc7,
-	0x72, 0x0c, 0x37, 0x1e, 0xcb, 0x31, 0x44, 0xd9, 0xa4, 0x67, 0x96, 0x64, 0x94, 0x26, 0xe9, 0x25,
-	0xe7, 0xe7, 0xea, 0x43, 0x7d, 0xa5, 0x9b, 0x93, 0x98, 0x54, 0x0c, 0xe3, 0xe8, 0x97, 0x19, 0x1a,
-	0xe9, 0x57, 0xe0, 0x08, 0x9f, 0x24, 0x36, 0xb0, 0xbb, 0x8d, 0x01, 0x01, 0x00, 0x00, 0xff, 0xff,
-	0x06, 0xb2, 0x0a, 0x2c, 0x48, 0x01, 0x00, 0x00,
+	// 460 bytes of a gzipped FileDescriptorProto
+	0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xb4, 0x93, 0x31, 0x6f, 0xd3, 0x40,
+	0x14, 0xc7, 0xed, 0x34, 0x4d, 0xd3, 0x2b, 0xaa, 0xda, 0x03, 0x21, 0xd3, 0xc1, 0x8e, 0x2c, 0x81,
+	0x3a, 0x10, 0x1b, 0x83, 0x58, 0x2a, 0xa6, 0x20, 0x86, 0x6c, 0x91, 0x41, 0x0c, 0x2c, 0xc1, 0xb9,
+	0x3b, 0xd2, 0xa7, 0x38, 0x77, 0xc9, 0xdd, 0xa5, 0x22, 0x7c, 0x02, 0x26, 0xc4, 0xc8, 0xd8, 0x0f,
+	0xc1, 0x67, 0x40, 0x15, 0x53, 0x47, 0xc4, 0x10, 0xa1, 0xe4, 0x1b, 0xf4, 0x13, 0x20, 0xdb, 0x17,
+	0xe3, 0x0c, 0x0c, 0x1d, 0x32, 0xd9, 0xef, 0xff, 0xee, 0xfd, 0x7f, 0x7f, 0xe9, 0xe9, 0xa1, 0xe7,
+	0x42, 0x8d, 0x85, 0x02, 0x15, 0x12, 0xc1, 0x09, 0xe3, 0x5a, 0x26, 0x9a, 0xd1, 0x76, 0x0a, 0xd3,
+	0x19, 0x50, 0xd0, 0xf3, 0x0d, 0xb9, 0x27, 0x44, 0x1a, 0x4c, 0xa4, 0xd0, 0x02, 0x3f, 0x34, 0x63,
+	0x41, 0xb5, 0x5f, 0x4e, 0x05, 0x17, 0xd1, 0x80, 0xe9, 0x24, 0x3a, 0x79, 0x40, 0xf2, 0x77, 0xfd,
+	0x7c, 0x28, 0x2c, 0x8a, 0xc2, 0xe1, 0xe4, 0xde, 0x50, 0x0c, 0x45, 0xa1, 0x67, 0x7f, 0x85, 0xea,
+	0xff, 0xd8, 0x41, 0xf5, 0x0c, 0x83, 0x1f, 0xa3, 0xbd, 0x84, 0x52, 0xc9, 0x94, 0x72, 0xec, 0x96,
+	0x7d, 0xba, 0xdf, 0xc1, 0x37, 0x0b, 0xef, 0x70, 0x9e, 0x8c, 0xd3, 0x33, 0xdf, 0x34, 0xfc, 0x78,
+	0xfd, 0x04, 0x1f, 0xa2, 0x1a, 0x50, 0xa7, 0xd6, 0xb2, 0x4f, 0xeb, 0x71, 0x0d, 0x28, 0x7e, 0x8f,
+	0xf6, 0xcb, 0x30, 0xce, 0x4e, 0x3e, 0xdf, 0xb9, 0x5a, 0x78, 0xd6, 0xef, 0x85, 0xf7, 0x68, 0x08,
+	0xfa, 0x7c, 0x36, 0x08, 0x88, 0x18, 0x9b, 0x40, 0xe6, 0xd3, 0x56, 0x74, 0x14, 0xea, 0xf9, 0x84,
+	0xa9, 0xa0, 0xcb, 0xf5, 0xcd, 0xc2, 0x3b, 0x2a, 0x68, 0xa5, 0x91, 0x1f, 0xff, 0x33, 0xc5, 0xf7,
+	0x51, 0x43, 0x8b, 0x11, 0xe3, 0x4f, 0x9c, 0x7a, 0x66, 0x1f, 0x9b, 0xaa, 0xd4, 0x23, 0x67, 0xb7,
+	0xa2, 0x47, 0x78, 0x8a, 0x30, 0x99, 0x49, 0xc9, 0xb8, 0xee, 0xab, 0xa9, 0xd4, 0xfd, 0x89, 0x04,
+	0xc2, 0x9c, 0x46, 0x1e, 0xed, 0xe5, 0xad, 0xa3, 0x1d, 0x17, 0xd1, 0xd4, 0x44, 0x18, 0x27, 0x3f,
+	0x3e, 0x32, 0xf6, 0xaf, 0xa7, 0x52, 0xf7, 0x32, 0x09, 0x9f, 0xa3, 0x3b, 0x6b, 0xa4, 0x06, 0x32,
+	0x72, 0xf6, 0x72, 0xd8, 0xab, 0x5b, 0xc3, 0xee, 0x16, 0xb0, 0xaa, 0x97, 0x1f, 0x1f, 0x98, 0xf2,
+	0x0d, 0x90, 0xd1, 0xd9, 0xf1, 0xe7, 0x4b, 0xcf, 0xfa, 0x76, 0xe9, 0x59, 0x3f, 0xbf, 0xb7, 0x77,
+	0xb3, 0xf5, 0x75, 0xfd, 0x2f, 0x36, 0x6a, 0x66, 0xbd, 0x2e, 0xff, 0x20, 0x70, 0x0b, 0x1d, 0x00,
+	0x07, 0x0d, 0x49, 0x0a, 0x9f, 0x18, 0xcd, 0x17, 0xda, 0x8c, 0xab, 0xd2, 0xe6, 0xc2, 0x6a, 0x5b,
+	0x58, 0x98, 0x9f, 0xa2, 0x66, 0x4f, 0x28, 0xd0, 0x20, 0xf8, 0x26, 0xcd, 0xde, 0x02, 0xad, 0xf3,
+	0xf6, 0x6a, 0xe9, 0xda, 0xd7, 0x4b, 0xd7, 0xfe, 0xb3, 0x74, 0xed, 0xaf, 0x2b, 0xd7, 0xba, 0x5e,
+	0xb9, 0xd6, 0xaf, 0x95, 0x6b, 0xbd, 0x7b, 0x51, 0x01, 0x98, 0x23, 0x6a, 0xa7, 0xc9, 0x40, 0xad,
+	0x8b, 0xf0, 0x22, 0x7a, 0x1a, 0x7e, 0xfc, 0xcf, 0x39, 0x0e, 0x1a, 0xf9, 0x99, 0x3c, 0xfb, 0x1b,
+	0x00, 0x00, 0xff, 0xff, 0x1d, 0x93, 0x31, 0x76, 0xb7, 0x03, 0x00, 0x00,
 }
 
 func (m *Pool) Marshal() (dAtA []byte, err error) {
@@ -114,6 +219,50 @@ func (m *Pool) MarshalToSizedBuffer(dAtA []byte) (int, error) {
 	_ = i
 	var l int
 	_ = l
+	{
+		size := m.CurrentTick.Size()
+		i -= size
+		if _, err := m.CurrentTick.MarshalTo(dAtA[i:]); err != nil {
+			return 0, err
+		}
+		i = encodeVarintConcentratedPool(dAtA, i, uint64(size))
+	}
+	i--
+	dAtA[i] = 0x3a
+	{
+		size := m.CurrentSqrtPrice.Size()
+		i -= size
+		if _, err := m.CurrentSqrtPrice.MarshalTo(dAtA[i:]); err != nil {
+			return 0, err
+		}
+		i = encodeVarintConcentratedPool(dAtA, i, uint64(size))
+	}
+	i--
+	dAtA[i] = 0x32
+	if len(m.Token1) > 0 {
+		i -= len(m.Token1)
+		copy(dAtA[i:], m.Token1)
+		i = encodeVarintConcentratedPool(dAtA, i, uint64(len(m.Token1)))
+		i--
+		dAtA[i] = 0x2a
+	}
+	if len(m.Token0) > 0 {
+		i -= len(m.Token0)
+		copy(dAtA[i:], m.Token0)
+		i = encodeVarintConcentratedPool(dAtA, i, uint64(len(m.Token0)))
+		i--
+		dAtA[i] = 0x22
+	}
+	{
+		size := m.Liquidity.Size()
+		i -= size
+		if _, err := m.Liquidity.MarshalTo(dAtA[i:]); err != nil {
+			return 0, err
+		}
+		i = encodeVarintConcentratedPool(dAtA, i, uint64(size))
+	}
+	i--
+	dAtA[i] = 0x1a
 	if m.Id != 0 {
 		i = encodeVarintConcentratedPool(dAtA, i, uint64(m.Id))
 		i--
@@ -129,6 +278,82 @@ func (m *Pool) MarshalToSizedBuffer(dAtA []byte) (int, error) {
 	return len(dAtA) - i, nil
 }
 
+func (m *TickInfo) Marshal() (dAtA []byte, err error) {
+	size := m.Size()
+	dAtA = make([]byte, size)
+	n, err := m.MarshalToSizedBuffer(dAtA[:size])
+	if err != nil {
+		return nil, err
+	}
+	return dAtA[:n], nil
+}
+
+func (m *TickInfo) MarshalTo(dAtA []byte) (int, error) {
+	size := m.Size()
+	return m.MarshalToSizedBuffer(dAtA[:size])
+}
+
+func (m *TickInfo) MarshalToSizedBuffer(dAtA []byte) (int, error) {
+	i := len(dAtA)
+	_ = i
+	var l int
+	_ = l
+	{
+		size := m.Liquidity.Size()
+		i -= size
+		if _, err := m.Liquidity.MarshalTo(dAtA[i:]); err != nil {
+			return 0, err
+		}
+		i = encodeVarintConcentratedPool(dAtA, i, uint64(size))
+	}
+	i--
+	dAtA[i] = 0x12
+	if m.Initialized {
+		i--
+		if m.Initialized {
+			dAtA[i] = 1
+		} else {
+			dAtA[i] = 0
+		}
+		i--
+		dAtA[i] = 0x8
+	}
+	return len(dAtA) - i, nil
+}
+
+func (m *Position) Marshal() (dAtA []byte, err error) {
+	size := m.Size()
+	dAtA = make([]byte, size)
+	n, err := m.MarshalToSizedBuffer(dAtA[:size])
+	if err != nil {
+		return nil, err
+	}
+	return dAtA[:n], nil
+}
+
+func (m *Position) MarshalTo(dAtA []byte) (int, error) {
+	size := m.Size()
+	return m.MarshalToSizedBuffer(dAtA[:size])
+}
+
+func (m *Position) MarshalToSizedBuffer(dAtA []byte) (int, error) {
+	i := len(dAtA)
+	_ = i
+	var l int
+	_ = l
+	{
+		size := m.Liquidity.Size()
+		i -= size
+		if _, err := m.Liquidity.MarshalTo(dAtA[i:]); err != nil {
+			return 0, err
+		}
+		i = encodeVarintConcentratedPool(dAtA, i, uint64(size))
+	}
+	i--
+	dAtA[i] = 0xa
+	return len(dAtA) - i, nil
+}
+
 func encodeVarintConcentratedPool(dAtA []byte, offset int, v uint64) int {
 	offset -= sovConcentratedPool(v)
 	base := offset
@@ -153,6 +378,45 @@ func (m *Pool) Size() (n int) {
 	if m.Id != 0 {
 		n += 1 + sovConcentratedPool(uint64(m.Id))
 	}
+	l = m.Liquidity.Size()
+	n += 1 + l + sovConcentratedPool(uint64(l))
+	l = len(m.Token0)
+	if l > 0 {
+		n += 1 + l + sovConcentratedPool(uint64(l))
+	}
+	l = len(m.Token1)
+	if l > 0 {
+		n += 1 + l + sovConcentratedPool(uint64(l))
+	}
+	l = m.CurrentSqrtPrice.Size()
+	n += 1 + l + sovConcentratedPool(uint64(l))
+	l = m.CurrentTick.Size()
+	n += 1 + l + sovConcentratedPool(uint64(l))
+	return n
+}
+
+func (m *TickInfo) Size() (n int) {
+	if m == nil {
+		return 0
+	}
+	var l int
+	_ = l
+	if m.Initialized {
+		n += 2
+	}
+	l = m.Liquidity.Size()
+	n += 1 + l + sovConcentratedPool(uint64(l))
+	return n
+}
+
+func (m *Position) Size() (n int) {
+	if m == nil {
+		return 0
+	}
+	var l int
+	_ = l
+	l = m.Liquidity.Size()
+	n += 1 + l + sovConcentratedPool(uint64(l))
 	return n
 }
 
@@ -242,6 +506,360 @@ func (m *Pool) Unmarshal(dAtA []byte) error {
 					break
 				}
 			}
+		case 3:
+			if wireType != 2 {
+				return fmt.Errorf("proto: wrong wireType = %d for field Liquidity", wireType)
+			}
+			var stringLen uint64
+			for shift := uint(0); ; shift += 7 {
+				if shift >= 64 {
+					return ErrIntOverflowConcentratedPool
+				}
+				if iNdEx >= l {
+					return io.ErrUnexpectedEOF
+				}
+				b := dAtA[iNdEx]
+				iNdEx++
+				stringLen |= uint64(b&0x7F) << shift
+				if b < 0x80 {
+					break
+				}
+			}
+			intStringLen := int(stringLen)
+			if intStringLen < 0 {
+				return ErrInvalidLengthConcentratedPool
+			}
+			postIndex := iNdEx + intStringLen
+			if postIndex < 0 {
+				return ErrInvalidLengthConcentratedPool
+			}
+			if postIndex > l {
+				return io.ErrUnexpectedEOF
+			}
+			if err := m.Liquidity.Unmarshal(dAtA[iNdEx:postIndex]); err != nil {
+				return err
+			}
+			iNdEx = postIndex
+		case 4:
+			if wireType != 2 {
+				return fmt.Errorf("proto: wrong wireType = %d for field Token0", wireType)
+			}
+			var stringLen uint64
+			for shift := uint(0); ; shift += 7 {
+				if shift >= 64 {
+					return ErrIntOverflowConcentratedPool
+				}
+				if iNdEx >= l {
+					return io.ErrUnexpectedEOF
+				}
+				b := dAtA[iNdEx]
+				iNdEx++
+				stringLen |= uint64(b&0x7F) << shift
+				if b < 0x80 {
+					break
+				}
+			}
+			intStringLen := int(stringLen)
+			if intStringLen < 0 {
+				return ErrInvalidLengthConcentratedPool
+			}
+			postIndex := iNdEx + intStringLen
+			if postIndex < 0 {
+				return ErrInvalidLengthConcentratedPool
+			}
+			if postIndex > l {
+				return io.ErrUnexpectedEOF
+			}
+			m.Token0 = string(dAtA[iNdEx:postIndex])
+			iNdEx = postIndex
+		case 5:
+			if wireType != 2 {
+				return fmt.Errorf("proto: wrong wireType = %d for field Token1", wireType)
+			}
+			var stringLen uint64
+			for shift := uint(0); ; shift += 7 {
+				if shift >= 64 {
+					return ErrIntOverflowConcentratedPool
+				}
+				if iNdEx >= l {
+					return io.ErrUnexpectedEOF
+				}
+				b := dAtA[iNdEx]
+				iNdEx++
+				stringLen |= uint64(b&0x7F) << shift
+				if b < 0x80 {
+					break
+				}
+			}
+			intStringLen := int(stringLen)
+			if intStringLen < 0 {
+				return ErrInvalidLengthConcentratedPool
+			}
+			postIndex := iNdEx + intStringLen
+			if postIndex < 0 {
+				return ErrInvalidLengthConcentratedPool
+			}
+			if postIndex > l {
+				return io.ErrUnexpectedEOF
+			}
+			m.Token1 = string(dAtA[iNdEx:postIndex])
+			iNdEx = postIndex
+		case 6:
+			if wireType != 2 {
+				return fmt.Errorf("proto: wrong wireType = %d for field CurrentSqrtPrice", wireType)
+			}
+			var stringLen uint64
+			for shift := uint(0); ; shift += 7 {
+				if shift >= 64 {
+					return ErrIntOverflowConcentratedPool
+				}
+				if iNdEx >= l {
+					return io.ErrUnexpectedEOF
+				}
+				b := dAtA[iNdEx]
+				iNdEx++
+				stringLen |= uint64(b&0x7F) << shift
+				if b < 0x80 {
+					break
+				}
+			}
+			intStringLen := int(stringLen)
+			if intStringLen < 0 {
+				return ErrInvalidLengthConcentratedPool
+			}
+			postIndex := iNdEx + intStringLen
+			if postIndex < 0 {
+				return ErrInvalidLengthConcentratedPool
+			}
+			if postIndex > l {
+				return io.ErrUnexpectedEOF
+			}
+			if err := m.CurrentSqrtPrice.Unmarshal(dAtA[iNdEx:postIndex]); err != nil {
+				return err
+			}
+			iNdEx = postIndex
+		case 7:
+			if wireType != 2 {
+				return fmt.Errorf("proto: wrong wireType = %d for field CurrentTick", wireType)
+			}
+			var stringLen uint64
+			for shift := uint(0); ; shift += 7 {
+				if shift >= 64 {
+					return ErrIntOverflowConcentratedPool
+				}
+				if iNdEx >= l {
+					return io.ErrUnexpectedEOF
+				}
+				b := dAtA[iNdEx]
+				iNdEx++
+				stringLen |= uint64(b&0x7F) << shift
+				if b < 0x80 {
+					break
+				}
+			}
+			intStringLen := int(stringLen)
+			if intStringLen < 0 {
+				return ErrInvalidLengthConcentratedPool
+			}
+			postIndex := iNdEx + intStringLen
+			if postIndex < 0 {
+				return ErrInvalidLengthConcentratedPool
+			}
+			if postIndex > l {
+				return io.ErrUnexpectedEOF
+			}
+			if err := m.CurrentTick.Unmarshal(dAtA[iNdEx:postIndex]); err != nil {
+				return err
+			}
+			iNdEx = postIndex
+		default:
+			iNdEx = preIndex
+			skippy, err := skipConcentratedPool(dAtA[iNdEx:])
+			if err != nil {
+				return err
+			}
+			if (skippy < 0) || (iNdEx+skippy) < 0 {
+				return ErrInvalidLengthConcentratedPool
+			}
+			if (iNdEx + skippy) > l {
+				return io.ErrUnexpectedEOF
+			}
+			iNdEx += skippy
+		}
+	}
+
+	if iNdEx > l {
+		return io.ErrUnexpectedEOF
+	}
+	return nil
+}
+func (m *TickInfo) Unmarshal(dAtA []byte) error {
+	l := len(dAtA)
+	iNdEx := 0
+	for iNdEx < l {
+		preIndex := iNdEx
+		var wire uint64
+		for shift := uint(0); ; shift += 7 {
+			if shift >= 64 {
+				return ErrIntOverflowConcentratedPool
+			}
+			if iNdEx >= l {
+				return io.ErrUnexpectedEOF
+			}
+			b := dAtA[iNdEx]
+			iNdEx++
+			wire |= uint64(b&0x7F) << shift
+			if b < 0x80 {
+				break
+			}
+		}
+		fieldNum := int32(wire >> 3)
+		wireType := int(wire & 0x7)
+		if wireType == 4 {
+			return fmt.Errorf("proto: TickInfo: wiretype end group for non-group")
+		}
+		if fieldNum <= 0 {
+			return fmt.Errorf("proto: TickInfo: illegal tag %d (wire type %d)", fieldNum, wire)
+		}
+		switch fieldNum {
+		case 1:
+			if wireType != 0 {
+				return fmt.Errorf("proto: wrong wireType = %d for field Initialized", wireType)
+			}
+			var v int
+			for shift := uint(0); ; shift += 7 {
+				if shift >= 64 {
+					return ErrIntOverflowConcentratedPool
+				}
+				if iNdEx >= l {
+					return io.ErrUnexpectedEOF
+				}
+				b := dAtA[iNdEx]
+				iNdEx++
+				v |= int(b&0x7F) << shift
+				if b < 0x80 {
+					break
+				}
+			}
+			m.Initialized = bool(v != 0)
+		case 2:
+			if wireType != 2 {
+				return fmt.Errorf("proto: wrong wireType = %d for field Liquidity", wireType)
+			}
+			var stringLen uint64
+			for shift := uint(0); ; shift += 7 {
+				if shift >= 64 {
+					return ErrIntOverflowConcentratedPool
+				}
+				if iNdEx >= l {
+					return io.ErrUnexpectedEOF
+				}
+				b := dAtA[iNdEx]
+				iNdEx++
+				stringLen |= uint64(b&0x7F) << shift
+				if b < 0x80 {
+					break
+				}
+			}
+			intStringLen := int(stringLen)
+			if intStringLen < 0 {
+				return ErrInvalidLengthConcentratedPool
+			}
+			postIndex := iNdEx + intStringLen
+			if postIndex < 0 {
+				return ErrInvalidLengthConcentratedPool
+			}
+			if postIndex > l {
+				return io.ErrUnexpectedEOF
+			}
+			if err := m.Liquidity.Unmarshal(dAtA[iNdEx:postIndex]); err != nil {
+				return err
+			}
+			iNdEx = postIndex
+		default:
+			iNdEx = preIndex
+			skippy, err := skipConcentratedPool(dAtA[iNdEx:])
+			if err != nil {
+				return err
+			}
+			if (skippy < 0) || (iNdEx+skippy) < 0 {
+				return ErrInvalidLengthConcentratedPool
+			}
+			if (iNdEx + skippy) > l {
+				return io.ErrUnexpectedEOF
+			}
+			iNdEx += skippy
+		}
+	}
+
+	if iNdEx > l {
+		return io.ErrUnexpectedEOF
+	}
+	return nil
+}
+func (m *Position) Unmarshal(dAtA []byte) error {
+	l := len(dAtA)
+	iNdEx := 0
+	for iNdEx < l {
+		preIndex := iNdEx
+		var wire uint64
+		for shift := uint(0); ; shift += 7 {
+			if shift >= 64 {
+				return ErrIntOverflowConcentratedPool
+			}
+			if iNdEx >= l {
+				return io.ErrUnexpectedEOF
+			}
+			b := dAtA[iNdEx]
+			iNdEx++
+			wire |= uint64(b&0x7F) << shift
+			if b < 0x80 {
+				break
+			}
+		}
+		fieldNum := int32(wire >> 3)
+		wireType := int(wire & 0x7)
+		if wireType == 4 {
+			return fmt.Errorf("proto: Position: wiretype end group for non-group")
+		}
+		if fieldNum <= 0 {
+			return fmt.Errorf("proto: Position: illegal tag %d (wire type %d)", fieldNum, wire)
+		}
+		switch fieldNum {
+		case 1:
+			if wireType != 2 {
+				return fmt.Errorf("proto: wrong wireType = %d for field Liquidity", wireType)
+			}
+			var stringLen uint64
+			for shift := uint(0); ; shift += 7 {
+				if shift >= 64 {
+					return ErrIntOverflowConcentratedPool
+				}
+				if iNdEx >= l {
+					return io.ErrUnexpectedEOF
+				}
+				b := dAtA[iNdEx]
+				iNdEx++
+				stringLen |= uint64(b&0x7F) << shift
+				if b < 0x80 {
+					break
+				}
+			}
+			intStringLen := int(stringLen)
+			if intStringLen < 0 {
+				return ErrInvalidLengthConcentratedPool
+			}
+			postIndex := iNdEx + intStringLen
+			if postIndex < 0 {
+				return ErrInvalidLengthConcentratedPool
+			}
+			if postIndex > l {
+				return io.ErrUnexpectedEOF
+			}
+			if err := m.Liquidity.Unmarshal(dAtA[iNdEx:postIndex]); err != nil {
+				return err
+			}
+			iNdEx = postIndex
 		default:
 			iNdEx = preIndex
 			skippy, err := skipConcentratedPool(dAtA[iNdEx:])
diff --git a/x/concentrated-liquidity/lp.go b/x/concentrated-liquidity/lp.go
index 1d4104c72..da3b65de3 100644
--- a/x/concentrated-liquidity/lp.go
+++ b/x/concentrated-liquidity/lp.go
@@ -1,6 +1,32 @@
 package concentrated_liquidity
 
-import sdk "github.com/cosmos/cosmos-sdk/types"
+import (
+	fmt "fmt"
+
+	sdk "github.com/cosmos/cosmos-sdk/types"
+
+	types "github.com/osmosis-labs/osmosis/v12/x/concentrated-liquidity/types"
+)
+
+func (k Keeper) Mint(ctx sdk.Context, poolId uint64, owner sdk.AccAddress, tokenIn sdk.Int, lowerTick sdk.Int, upperTick sdk.Int) (numShares sdk.Int, err error) {
+	// first check and validate arguments
+	if lowerTick.GTE(types.MaxTick) || lowerTick.LT(types.MinTick) || upperTick.GT(types.MaxTick) {
+		// TODO: come back to errors
+		return sdk.Int{}, fmt.Errorf("validation fail")
+	}
+
+	if tokenIn.IsZero() {
+		return sdk.Int{}, fmt.Errorf("token in amount is zero")
+	}
+
+	k.UpdateTickWithNewLiquidity(ctx, poolId, lowerTick, tokenIn)
+	k.UpdateTickWithNewLiquidity(ctx, poolId, upperTick, tokenIn)
+
+	// update tick with new liquidity
+	k.updatePositionWithLiquidity(ctx, poolId, owner.String(), lowerTick, upperTick, tokenIn)
+
+	return sdk.Int{}, nil
+}
 
 func (k Keeper) JoinPoolNoSwap(ctx sdk.Context, tokensIn sdk.Coins, swapFee sdk.Dec) (numShares sdk.Int, err error) {
 	return sdk.Int{}, nil
diff --git a/x/concentrated-liquidity/pool.go b/x/concentrated-liquidity/pool.go
index 52d6d6ee2..0094986a4 100644
--- a/x/concentrated-liquidity/pool.go
+++ b/x/concentrated-liquidity/pool.go
@@ -32,7 +32,7 @@ func liquidity0(amount int64, pa, pb sdk.Dec) sdk.Dec {
 	if pa.GT(pb) {
 		pa, pb = pb, pa
 	}
-	product := pa.Mul(pb).Quo(sdk.NewDec(10).Power(6))
+	product := pa.Mul(pb)
 	diff := pb.Sub(pa)
 	amt := sdk.NewDec(amount)
 	return amt.Mul(product.Quo(diff))
@@ -47,7 +47,7 @@ func liquidity1(amount int64, pa, pb sdk.Dec) sdk.Dec {
 	}
 	diff := pb.Sub(pa)
 	amt := sdk.NewDec(amount)
-	return amt.Quo(diff).Mul(sdk.NewDec(10).Power(6))
+	return amt.Quo(diff)
 }
 
 // calcAmount0 takes the asset with the smaller liqudity in the pool as well as the sqrtpCur and the nextPrice and calculates the amount of asset 0
@@ -58,7 +58,7 @@ func calcAmount0(liq, pa, pb sdk.Dec) sdk.Dec {
 		pa, pb = pb, pa
 	}
 	diff := pb.Sub(pa)
-	mult := liq.Mul(sdk.NewDec(10).Power(6))
+	mult := liq
 	return (mult.Mul(diff)).Quo(pb).Quo(pa)
 }
 
@@ -70,7 +70,7 @@ func calcAmount1(liq, pa, pb sdk.Dec) sdk.Dec {
 		pa, pb = pb, pa
 	}
 	diff := pb.Sub(pa)
-	return liq.Mul(diff).Quo(sdk.NewDec(10).Power(6))
+	return liq.Mul(diff)
 }
 
 func (p Pool) GetAddress() sdk.AccAddress {
@@ -113,9 +113,9 @@ func (p Pool) CalcOutAmtGivenIn(ctx sdk.Context, tokensIn sdk.Coins, tokenOutDen
 	tokenAmountInAfterFee := tokenIn.Amount.ToDec().Mul(sdk.OneDec().Sub(swapFee))
 
 	// TODO: Replace with spot price
-	priceLower := sdk.NewDec(4500000000)
-	priceCur := sdk.NewDec(5000000000)
-	priceUpper := sdk.NewDec(5500000000)
+	priceLower := sdk.NewDec(4500)
+	priceCur := sdk.NewDec(5000)
+	priceUpper := sdk.NewDec(5500)
 
 	sqrtPLowerTick, _ := priceLower.ApproxSqrt()
 	sqrtPCurTick, _ := priceCur.ApproxSqrt()
@@ -137,13 +137,12 @@ func (p Pool) CalcOutAmtGivenIn(ctx sdk.Context, tokensIn sdk.Coins, tokenOutDen
 		amountOut := calcAmount0(liq, priceNext, sqrtPCurTick)
 		return sdk.NewCoin(tokenOutDenom, amountOut.TruncateInt()), nil
 	} else if tokenIn.Denom == asset0 {
-		priceNextTop := liq.Mul(sdk.NewDec(10).Power(6).Mul(sqrtPCurTick))
-		priceNextBot := liq.Mul(sdk.NewDec(10).Power(6)).Add(tokenAmountInAfterFee.Mul(sqrtPCurTick))
+		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 := calcAmount1(liq, priceNext, sqrtPCurTick)
-		amountOut = amountOut.Mul(sdk.NewDec(10).Power(6))
 		return sdk.NewCoin(tokenOutDenom, amountOut.TruncateInt()), nil
 	}
 	return sdk.Coin{}, fmt.Errorf("tokenIn does not match any asset in pool")
@@ -160,9 +159,9 @@ func (p Pool) CalcInAmtGivenOut(ctx sdk.Context, tokensOut sdk.Coins, tokenInDen
 	asset1 := "usdc"
 
 	// TODO: Replace with spot price
-	priceLower := sdk.NewDec(4500000000)
-	priceCur := sdk.NewDec(5000000000)
-	priceUpper := sdk.NewDec(5500000000)
+	priceLower := sdk.NewDec(4500)
+	priceCur := sdk.NewDec(5000)
+	priceUpper := sdk.NewDec(5500)
 
 	sqrtPLowerTick, _ := priceLower.ApproxSqrt()
 	sqrtPCurTick, _ := priceCur.ApproxSqrt()
@@ -188,14 +187,13 @@ func (p Pool) CalcInAmtGivenOut(ctx sdk.Context, tokensOut sdk.Coins, tokenInDen
 		amountIn = amountIn.Quo(sdk.OneDec().Sub(swapFee))
 		return sdk.NewCoin(tokenInDenom, amountIn.TruncateInt()), nil
 	} else if tokenOut.Denom == asset0 {
-		priceNextTop := liq.Mul(sdk.NewDec(10).Power(6).Mul(sqrtPCurTick))
-		priceNextBot := liq.Mul(sdk.NewDec(10).Power(6)).Add(tokenOutAmt.Mul(sqrtPCurTick))
+		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 := calcAmount1(liq, priceNext, sqrtPCurTick)
-		amountIn = amountIn.Mul(sdk.NewDec(10).Power(6))
 		// fee logic
 		amountIn = amountIn.Quo(sdk.OneDec().Sub(swapFee))
 		return sdk.NewCoin(tokenInDenom, amountIn.TruncateInt()), nil
diff --git a/x/concentrated-liquidity/position.go b/x/concentrated-liquidity/position.go
new file mode 100644
index 000000000..6505b3a0b
--- /dev/null
+++ b/x/concentrated-liquidity/position.go
@@ -0,0 +1,41 @@
+package concentrated_liquidity
+
+import (
+	sdk "github.com/cosmos/cosmos-sdk/types"
+
+	"github.com/osmosis-labs/osmosis/v12/osmoutils"
+	types "github.com/osmosis-labs/osmosis/v12/x/concentrated-liquidity/types"
+)
+
+func (k Keeper) updatePositionWithLiquidity(ctx sdk.Context,
+	poolId uint64,
+	owner string,
+	lowerTick, upperTick sdk.Int,
+	liquidityDelta sdk.Int) {
+	position := k.getPosition(ctx, poolId, owner, lowerTick, upperTick)
+
+	liquidityBefore := position.Liquidity
+	liquidityAfter := liquidityBefore.Add(liquidityDelta)
+	position.Liquidity = liquidityAfter
+
+	k.setPosition(ctx, poolId, owner, lowerTick, upperTick, position)
+}
+
+func (k Keeper) getPosition(ctx sdk.Context, poolId uint64, owner string, lowerTick, upperTick sdk.Int) Position {
+	store := ctx.KVStore(k.storeKey)
+	position := Position{}
+	key := types.KeyPosition(poolId, owner, lowerTick, upperTick)
+	osmoutils.MustGet(store, key, &position)
+	return position
+}
+
+func (k Keeper) setPosition(ctx sdk.Context,
+	poolId uint64,
+	owner string,
+	lowerTick, upperTick sdk.Int,
+	position Position) {
+	store := ctx.KVStore(k.storeKey)
+
+	key := types.KeyPosition(poolId, owner, lowerTick, upperTick)
+	osmoutils.MustSet(store, key, &position)
+}
diff --git a/x/concentrated-liquidity/tick.go b/x/concentrated-liquidity/tick.go
new file mode 100644
index 000000000..bc3bd206d
--- /dev/null
+++ b/x/concentrated-liquidity/tick.go
@@ -0,0 +1,37 @@
+package concentrated_liquidity
+
+import (
+	sdk "github.com/cosmos/cosmos-sdk/types"
+
+	"github.com/osmosis-labs/osmosis/v12/osmoutils"
+	types "github.com/osmosis-labs/osmosis/v12/x/concentrated-liquidity/types"
+)
+
+func (k Keeper) UpdateTickWithNewLiquidity(ctx sdk.Context, poolId uint64, tickIndex sdk.Int, liquidityDelta sdk.Int) {
+	tickInfo := k.getTickInfo(ctx, poolId, tickIndex)
+
+	liquidityBefore := tickInfo.Liquidity
+	liquidityAfter := liquidityBefore.Add(liquidityDelta)
+
+	tickInfo.Liquidity = liquidityAfter
+
+	if liquidityBefore == sdk.ZeroInt() {
+		tickInfo.Initialized = true
+	}
+
+	k.setTickInfo(ctx, poolId, tickIndex, tickInfo)
+}
+
+func (k Keeper) getTickInfo(ctx sdk.Context, poolId uint64, tickIndex sdk.Int) TickInfo {
+	store := ctx.KVStore(k.storeKey)
+	tickInfo := TickInfo{}
+	key := types.KeyTick(poolId, tickIndex)
+	osmoutils.MustGet(store, key, &tickInfo)
+	return tickInfo
+}
+
+func (k Keeper) setTickInfo(ctx sdk.Context, poolId uint64, tickIndex sdk.Int, tickInfo TickInfo) {
+	store := ctx.KVStore(k.storeKey)
+	key := types.KeyTick(poolId, tickIndex)
+	osmoutils.MustSet(store, key, &tickInfo)
+}
diff --git a/x/concentrated-liquidity/types/constants.go b/x/concentrated-liquidity/types/constants.go
new file mode 100644
index 000000000..dc076c217
--- /dev/null
+++ b/x/concentrated-liquidity/types/constants.go
@@ -0,0 +1,11 @@
+package types
+
+import (
+	sdk "github.com/cosmos/cosmos-sdk/types"
+)
+
+// TODO: decide on the values for Max tick and Min tick
+var (
+	MaxTick = sdk.NewIntFromUint64(887272)
+	MinTick = MaxTick.Neg()
+)
diff --git a/x/concentrated-liquidity/types/keys.go b/x/concentrated-liquidity/types/keys.go
new file mode 100644
index 000000000..5c5647fde
--- /dev/null
+++ b/x/concentrated-liquidity/types/keys.go
@@ -0,0 +1,34 @@
+package types
+
+import (
+	"fmt"
+
+	sdk "github.com/cosmos/cosmos-sdk/types"
+)
+
+const (
+	ModuleName = "twap"
+
+	StoreKey          = ModuleName
+	TransientStoreKey = "transient_" + ModuleName // this is silly we have to do this
+	RouterKey         = ModuleName
+
+	QuerierRoute = ModuleName
+	// Contract: Coin denoms cannot contain this character
+	KeySeparator = "|"
+)
+
+var (
+	TickPrefix     = "tick_prefix" + KeySeparator
+	PositionPrefix = "position_prefix" + KeySeparator
+)
+
+// KeyTick uses pool Id and tick index
+func KeyTick(poolId uint64, tickIndex sdk.Int) []byte {
+	return []byte(fmt.Sprintf("%s%d%s", TickPrefix, poolId, tickIndex.String()))
+}
+
+// KeyPosition uses pool Id, owner, lower tick and upper tick for keys
+func KeyPosition(poolId uint64, address string, lowerTick, upperTick sdk.Int) []byte {
+	return []byte(fmt.Sprintf("%s%d%s%s%s", PositionPrefix, poolId, address, lowerTick.String(), upperTick.String()))
+}


Test patch:
diff --git a/osmomath/decimal_test.go b/osmomath/decimal_test.go
index 1650186dd..92b886d1d 100644
--- a/osmomath/decimal_test.go
+++ b/osmomath/decimal_test.go
@@ -11,6 +11,8 @@ import (
 	"github.com/stretchr/testify/require"
 	"github.com/stretchr/testify/suite"
 	"gopkg.in/yaml.v2"
+
+	"github.com/osmosis-labs/osmosis/v12/app/apptesting/osmoassert"
 )
 
 type decimalTestSuite struct {
@@ -152,8 +154,8 @@ func (s *decimalTestSuite) TestDecFloat64() {
 
 func (s *decimalTestSuite) TestSdkDec() {
 	tests := []struct {
-		d    BigDec
-		want sdk.Dec
+		d        BigDec
+		want     sdk.Dec
 		expPanic bool
 	}{
 		{NewBigDec(0), sdk.MustNewDecFromStr("0.000000000000000000"), false},
@@ -177,8 +179,8 @@ func (s *decimalTestSuite) TestSdkDec() {
 
 func (s *decimalTestSuite) TestBigDecFromSdkDec() {
 	tests := []struct {
-		d    sdk.Dec
-		want BigDec
+		d        sdk.Dec
+		want     BigDec
 		expPanic bool
 	}{
 		{sdk.MustNewDecFromStr("0.000000000000000000"), NewBigDec(0), false},
@@ -441,14 +443,14 @@ func (s *decimalTestSuite) TestDecCeil() {
 		input    BigDec
 		expected BigDec
 	}{
-		{MustNewDecFromStr("0.001"), NewBigDec(1)}, // 0.001 => 1.0
-		{MustNewDecFromStr("-0.001"), ZeroDec()},   // -0.001 => 0.0
-		{ZeroDec(), ZeroDec()}, // 0.0 => 0.0
-		{MustNewDecFromStr("0.9"), NewBigDec(1)},    // 0.9 => 1.0
+		{MustNewDecFromStr("0.001"), NewBigDec(1)},   // 0.001 => 1.0
+		{MustNewDecFromStr("-0.001"), ZeroDec()},     // -0.001 => 0.0
+		{ZeroDec(), ZeroDec()},                       // 0.0 => 0.0
+		{MustNewDecFromStr("0.9"), NewBigDec(1)},     // 0.9 => 1.0
 		{MustNewDecFromStr("4.001"), NewBigDec(5)},   // 4.001 => 5.0
 		{MustNewDecFromStr("-4.001"), NewBigDec(-4)}, // -4.001 => -4.0
-		{MustNewDecFromStr("4.7"), NewBigDec(5)},   // 4.7 => 5.0
-		{MustNewDecFromStr("-4.7"), NewBigDec(-4)}, // -4.7 => -4.0
+		{MustNewDecFromStr("4.7"), NewBigDec(5)},     // 4.7 => 5.0
+		{MustNewDecFromStr("-4.7"), NewBigDec(-4)},   // -4.7 => -4.0
 	}
 
 	for i, tc := range testCases {
@@ -463,11 +465,11 @@ func (s *decimalTestSuite) TestPower() {
 		power    uint64
 		expected BigDec
 	}{
-		{OneDec(), 10, OneDec()},                                               // 1.0 ^ (10) => 1.0
-		{NewDecWithPrec(5, 1), 2, NewDecWithPrec(25, 2)},                       // 0.5 ^ 2 => 0.25
-		{NewDecWithPrec(2, 1), 2, NewDecWithPrec(4, 2)},                        // 0.2 ^ 2 => 0.04
-		{NewDecFromInt(NewInt(3)), 3, NewDecFromInt(NewInt(27))},               // 3 ^ 3 => 27
-		{NewDecFromInt(NewInt(-3)), 4, NewDecFromInt(NewInt(81))},              // -3 ^ 4 = 81
+		{OneDec(), 10, OneDec()},                                                                   // 1.0 ^ (10) => 1.0
+		{NewDecWithPrec(5, 1), 2, NewDecWithPrec(25, 2)},                                           // 0.5 ^ 2 => 0.25
+		{NewDecWithPrec(2, 1), 2, NewDecWithPrec(4, 2)},                                            // 0.2 ^ 2 => 0.04
+		{NewDecFromInt(NewInt(3)), 3, NewDecFromInt(NewInt(27))},                                   // 3 ^ 3 => 27
+		{NewDecFromInt(NewInt(-3)), 4, NewDecFromInt(NewInt(81))},                                  // -3 ^ 4 = 81
 		{MustNewDecFromStr("1.414213562373095048801688724209698079"), 2, NewDecFromInt(NewInt(2))}, // 1.414213562373095048801688724209698079 ^ 2 = 2
 	}
 
@@ -483,14 +485,14 @@ func (s *decimalTestSuite) TestApproxRoot() {
 		root     uint64
 		expected BigDec
 	}{
-		{OneDec(), 10, OneDec()},                                                       // 1.0 ^ (0.1) => 1.0
-		{NewDecWithPrec(25, 2), 2, NewDecWithPrec(5, 1)},                               // 0.25 ^ (0.5) => 0.5
-		{NewDecWithPrec(4, 2), 2, NewDecWithPrec(2, 1)},                                // 0.04 ^ (0.5) => 0.2
-		{NewDecFromInt(NewInt(27)), 3, NewDecFromInt(NewInt(3))},                       // 27 ^ (1/3) => 3
-		{NewDecFromInt(NewInt(-81)), 4, NewDecFromInt(NewInt(-3))},                     // -81 ^ (0.25) => -3
-		{NewDecFromInt(NewInt(2)), 2, MustNewDecFromStr("1.414213562373095048801688724209698079")},         // 2 ^ (0.5) => 1.414213562373095048801688724209698079
+		{OneDec(), 10, OneDec()},                                                                         // 1.0 ^ (0.1) => 1.0
+		{NewDecWithPrec(25, 2), 2, NewDecWithPrec(5, 1)},                                                 // 0.25 ^ (0.5) => 0.5
+		{NewDecWithPrec(4, 2), 2, NewDecWithPrec(2, 1)},                                                  // 0.04 ^ (0.5) => 0.2
+		{NewDecFromInt(NewInt(27)), 3, NewDecFromInt(NewInt(3))},                                         // 27 ^ (1/3) => 3
+		{NewDecFromInt(NewInt(-81)), 4, NewDecFromInt(NewInt(-3))},                                       // -81 ^ (0.25) => -3
+		{NewDecFromInt(NewInt(2)), 2, MustNewDecFromStr("1.414213562373095048801688724209698079")},       // 2 ^ (0.5) => 1.414213562373095048801688724209698079
 		{NewDecWithPrec(1005, 3), 31536000, MustNewDecFromStr("1.000000000158153903837946258002096839")}, // 1.005 ^ (1/31536000) ≈ 1.000000000158153903837946258002096839
-		{SmallestDec(), 2, NewDecWithPrec(1, 18)},                                       // 1e-36 ^ (0.5) => 1e-18
+		{SmallestDec(), 2, NewDecWithPrec(1, 18)},                                                        // 1e-36 ^ (0.5) => 1e-18
 		{SmallestDec(), 3, MustNewDecFromStr("0.000000000001000000000000000002431786")},                  // 1e-36 ^ (1/3) => 1e-12
 		{NewDecWithPrec(1, 8), 3, MustNewDecFromStr("0.002154434690031883721759293566519280")},           // 1e-8 ^ (1/3) ≈ 0.002154434690031883721759293566519
 	}
@@ -511,11 +513,11 @@ func (s *decimalTestSuite) TestApproxSqrt() {
 		input    BigDec
 		expected BigDec
 	}{
-		{OneDec(), OneDec()},                                                // 1.0 => 1.0
-		{NewDecWithPrec(25, 2), NewDecWithPrec(5, 1)},                       // 0.25 => 0.5
-		{NewDecWithPrec(4, 2), NewDecWithPrec(2, 1)},                        // 0.09 => 0.3
-		{NewDecFromInt(NewInt(9)), NewDecFromInt(NewInt(3))},                // 9 => 3
-		{NewDecFromInt(NewInt(-9)), NewDecFromInt(NewInt(-3))},              // -9 => -3
+		{OneDec(), OneDec()},                                                                    // 1.0 => 1.0
+		{NewDecWithPrec(25, 2), NewDecWithPrec(5, 1)},                                           // 0.25 => 0.5
+		{NewDecWithPrec(4, 2), NewDecWithPrec(2, 1)},                                            // 0.09 => 0.3
+		{NewDecFromInt(NewInt(9)), NewDecFromInt(NewInt(3))},                                    // 9 => 3
+		{NewDecFromInt(NewInt(-9)), NewDecFromInt(NewInt(-3))},                                  // -9 => -3
 		{NewDecFromInt(NewInt(2)), MustNewDecFromStr("1.414213562373095048801688724209698079")}, // 2 => 1.414213562373095048801688724209698079
 	}
 
@@ -650,3 +652,62 @@ func BenchmarkMarshalTo(b *testing.B) {
 		}
 	}
 }
+
+func (s *decimalTestSuite) TestLog2() {
+
+	tests := map[string]struct {
+		initialValue BigDec
+		expected     BigDec
+
+		expectedPanic bool
+	}{
+		"log_2{0.99}; not supported; panic": {
+			initialValue: NewDecWithPrec(99, 2),
+
+			expectedPanic: true,
+		},
+		"log_2{1} = 0": {
+			initialValue: NewBigDec(1),
+			expected:     NewBigDec(0),
+		},
+		"log_2{2} = 1": {
+			initialValue: NewBigDec(2),
+			expected:     NewBigDec(1),
+		},
+		"log_2{512} = 9": {
+			initialValue: NewBigDec(512),
+			expected:     NewBigDec(9),
+		},
+		"log_2{600} = 9": {
+			initialValue: NewBigDec(580),
+			// TODO: true value is: 9.179909090014934468590092754117374938
+			// Need better lookup table.
+			expected: MustNewDecFromStr("9.137503523749934908329043617236402782"),
+		},
+		"log_2{1024} = 10": {
+			initialValue: NewBigDec(1024),
+			expected:     NewBigDec(10),
+		},
+		"log_2{1024.987654321} = 10": {
+			initialValue: NewDecWithPrec(1024987654321, 9),
+			// TODO: true value is: 10.001390817654141324352719749259888355
+			// Need better lookup table
+			expected: MustNewDecFromStr("10.000000000000000000000000000000000000"),
+		},
+		"log_2{912648174127941279170121098210.92821920190204131121} = 99.525973560175362367047484597337715868": {
+			initialValue: MustNewDecFromStr("912648174127941279170121098210.92821920190204131121"),
+			// TODO: true value is: 99.525973560175362367047484597337715868
+			// Need better lookup table
+			expected: MustNewDecFromStr("99.485426827170241759571649887742440632"),
+		},
+	}
+
+	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)
+			})
+		})
+	}
+}
diff --git a/osmomath/log2_bench_test.go b/osmomath/log2_bench_test.go
new file mode 100644
index 000000000..1a723be16
--- /dev/null
+++ b/osmomath/log2_bench_test.go
@@ -0,0 +1,34 @@
+package osmomath
+
+import (
+	"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"),
+		},
+	}
+
+	for i := 0; i < b.N; i++ {
+		for _, test := range tests {
+			test.value.ApproxLog2()
+		}
+	}
+}
diff --git a/x/concentrated-liquidity/pool_test.go b/x/concentrated-liquidity/pool_test.go
index 87cc69964..50b656595 100644
--- a/x/concentrated-liquidity/pool_test.go
+++ b/x/concentrated-liquidity/pool_test.go
@@ -19,7 +19,7 @@ func TestCalcOutAmtGivenIn(t *testing.T) {
 	swapFee := sdk.NewDec(0)
 
 	amountOut, _ := pool.CalcOutAmtGivenIn(ctx, tokensIn, tokenOutDenom, swapFee)
-	require.Equal(t, sdk.NewDec(664366278), amountOut.Amount.ToDec())
+	require.Equal(t, sdk.NewDec(663944647).String(), amountOut.Amount.ToDec().String())
 
 	// test asset b to a logic
 	tokensIn = sdk.NewCoins(sdk.NewCoin("usdc", sdk.NewInt(4199999999)))
@@ -27,7 +27,7 @@ func TestCalcOutAmtGivenIn(t *testing.T) {
 	swapFee = sdk.NewDec(0)
 
 	amountOut, _ = pool.CalcOutAmtGivenIn(ctx, tokensIn, tokenOutDenom, swapFee)
-	require.Equal(t, sdk.NewDec(808398), amountOut.Amount.ToDec())
+	require.Equal(t, sdk.NewDec(805287), amountOut.Amount.ToDec())
 
 	// test with swap fee
 	tokensIn = sdk.NewCoins(sdk.NewCoin("usdc", sdk.NewInt(4199999999)))
@@ -35,7 +35,7 @@ func TestCalcOutAmtGivenIn(t *testing.T) {
 	swapFee = sdk.NewDecWithPrec(2, 2)
 
 	amountOut, _ = pool.CalcOutAmtGivenIn(ctx, tokensIn, tokenOutDenom, swapFee)
-	require.Equal(t, sdk.NewDec(792827), amountOut.Amount.ToDec())
+	require.Equal(t, sdk.NewDec(789834), amountOut.Amount.ToDec())
 }
 
 func TestCalcInAmtGivenOut(t *testing.T) {
@@ -49,7 +49,7 @@ func TestCalcInAmtGivenOut(t *testing.T) {
 
 	amountIn, err := pool.CalcInAmtGivenOut(ctx, tokensOut, tokenInDenom, swapFee)
 	require.NoError(t, err)
-	require.Equal(t, sdk.NewDec(808398), amountIn.Amount.ToDec())
+	require.Equal(t, sdk.NewDec(805287), amountIn.Amount.ToDec())
 
 	// test asset b to a logic
 	tokensOut = sdk.NewCoins(sdk.NewCoin("eth", sdk.NewInt(133700)))
@@ -58,7 +58,7 @@ func TestCalcInAmtGivenOut(t *testing.T) {
 
 	amountIn, err = pool.CalcInAmtGivenOut(ctx, tokensOut, tokenInDenom, swapFee)
 	require.NoError(t, err)
-	require.Equal(t, sdk.NewDec(664366278), amountIn.Amount.ToDec())
+	require.Equal(t, sdk.NewDec(663944647), amountIn.Amount.ToDec())
 
 	// test asset a to b logic
 	tokensOut = sdk.NewCoins(sdk.NewCoin("usdc", sdk.NewInt(4199999999)))
@@ -66,5 +66,5 @@ func TestCalcInAmtGivenOut(t *testing.T) {
 	swapFee = sdk.NewDecWithPrec(2, 2)
 
 	amountIn, _ = pool.CalcInAmtGivenOut(ctx, tokensOut, tokenInDenom, swapFee)
-	require.Equal(t, sdk.NewDec(824896), amountIn.Amount.ToDec())
+	require.Equal(t, sdk.NewDec(821721), amountIn.Amount.ToDec())
 }