Skip to content

Commit

Permalink
feat: change type for tickRatio and binaryLog
Browse files Browse the repository at this point in the history
  • Loading branch information
notJoon committed Dec 22, 2024
1 parent 71a0c2d commit 0b3e850
Showing 1 changed file with 140 additions and 49 deletions.
189 changes: 140 additions & 49 deletions _deploy/r/gnoswap/common/tick_math.gno
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
package common

import (
"gno.land/p/demo/avl"
"gno.land/p/demo/ufmt"

i256 "gno.land/p/gnoswap/int256"
Expand All @@ -22,47 +23,127 @@ const (
Q128 string = "340282366920938463463374607431768211456" // 2 ** 128
)

// TODO:
// 1. change avl.Tree
var tickRatioMap = map[int32]*u256.Uint{
0x1: u256.MustFromDecimal("340265354078544963557816517032075149313"), // 0xfffcb933bd6fad37aa2d162d1a594001,
0x2: u256.MustFromDecimal("340248342086729790484326174814286782778"), // 0xfff97272373d413259a46990580e213a,
0x4: u256.MustFromDecimal("340214320654664324051920982716015181260"), // 0xfff2e50f5f656932ef12357cf3c7fdcc,
0x8: u256.MustFromDecimal("340146287995602323631171512101879684304"), // 0xffe5caca7e10e4e61c3624eaa0941cd0,
0x10: u256.MustFromDecimal("340010263488231146823593991679159461444"), // 0xffcb9843d60f6159c9db58835c926644,
0x20: u256.MustFromDecimal("339738377640345403697157401104375502016"), // 0xff973b41fa98c081472e6896dfb254c0,
0x40: u256.MustFromDecimal("339195258003219555707034227454543997025"), // 0xff2ea16466c96a3843ec78b326b52861,
0x80: u256.MustFromDecimal("338111622100601834656805679988414885971"), // 0xfe5dee046a99a2a811c461f1969c3053,
0x100: u256.MustFromDecimal("335954724994790223023589805789778977700"), // 0xfcbe86c7900a88aedcffc83b479aa3a4,
0x200: u256.MustFromDecimal("331682121138379247127172139078559817300"), // 0xf987a7253ac413176f2b074cf7815e54,
0x400: u256.MustFromDecimal("323299236684853023288211250268160618739"), // 0xf3392b0822b70005940c7a398e4b70f3,
0x800: u256.MustFromDecimal("307163716377032989948697243942600083929"), // 0xe7159475a2c29b7443b29c7fa6e889d9,
0x1000: u256.MustFromDecimal("277268403626896220162999269216087595045"), // 0xd097f3bdfd2022b8845ad8f792aa5825,
0x2000: u256.MustFromDecimal("225923453940442621947126027127485391333"), // 0xa9f746462d870fdf8a65dc1f90e061e5,
0x4000: u256.MustFromDecimal("149997214084966997727330242082538205943"), // 0x70d869a156d2a1b890bb3df62baf32f7,
0x8000: u256.MustFromDecimal("66119101136024775622716233608466517926"), // 0x31be135f97d08fd981231505542fcfa6,
0x10000: u256.MustFromDecimal("12847376061809297530290974190478138313"), // 0x9aa508b5b7a84e1c677de54f3e99bc9,
0x20000: u256.MustFromDecimal("485053260817066172746253684029974020"), // 0x5d6af8dedb81196699c329225ee604,
0x40000: u256.MustFromDecimal("691415978906521570653435304214168"), // 0x2216e584f5fa1ea926041bedfe98,
0x80000: u256.MustFromDecimal("1404880482679654955896180642"), // 0x48a170391f7dc42444e8fa2,
}

var binaryLogConsts = [8]*u256.Uint{
u256.MustFromDecimal("0"), // 0x0,
u256.MustFromDecimal("3"), // 0x3,
u256.MustFromDecimal("15"), // 0xF,
u256.MustFromDecimal("255"), // 0xFF,
u256.MustFromDecimal("65535"), // 0xFFFF,
u256.MustFromDecimal("4294967295"), // 0xFFFFFFFF,
u256.MustFromDecimal("18446744073709551615"), // 0xFFFFFFFFFFFFFFFF,
u256.MustFromDecimal("340282366920938463463374607431768211455"), // 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF,
}

var (
tickRatioTree = NewTickRatioTree()
binaryLogTree = NewBinaryLogTree()

shift1By32Left = u256.MustFromDecimal("4294967296") // (1 << 32)
maxTick = int32(887272)
)

// TreeValue wraps u256.Uint to implement custom value type for avl.Tree
type TreeValue struct {
value *u256.Uint
}

func (tv TreeValue) String() string {
return tv.value.ToString()
}

// TickRatioTree manages tick ratios
type TickRatioTree struct {
tree *avl.Tree
}

// NewTickRatioTree initializes a new TickRatioTree with predefined values
func NewTickRatioTree() *TickRatioTree {
tree := avl.NewTree()

ratios := []struct {
key int32
value string
}{
{0x1, "340265354078544963557816517032075149313"},
{0x2, "340248342086729790484326174814286782778"},
{0x4, "340214320654664324051920982716015181260"},
{0x8, "340146287995602323631171512101879684304"},
{0x10, "340010263488231146823593991679159461444"},
{0x20, "339738377640345403697157401104375502016"},
{0x40, "339195258003219555707034227454543997025"},
{0x80, "338111622100601834656805679988414885971"},
{0x100, "335954724994790223023589805789778977700"},
{0x200, "331682121138379247127172139078559817300"},
{0x400, "323299236684853023288211250268160618739"},
{0x800, "307163716377032989948697243942600083929"},
{0x1000, "277268403626896220162999269216087595045"},
{0x2000, "225923453940442621947126027127485391333"},
{0x4000, "149997214084966997727330242082538205943"},
{0x8000, "66119101136024775622716233608466517926"},
{0x10000, "12847376061809297530290974190478138313"},
{0x20000, "485053260817066172746253684029974020"},
{0x40000, "691415978906521570653435304214168"},
{0x80000, "1404880482679654955896180642"},
}

for _, ratio := range ratios {
tick := ufmt.Sprintf("%d", ratio.key)
value := TreeValue{u256.MustFromDecimal(ratio.value)}
tree.Set(tick, value)
}

return &TickRatioTree{tree}
}

// GetRatio retrieves the ratio for a given tick
func (t *TickRatioTree) GetRatio(key int32) (*u256.Uint, bool) {
strKey := ufmt.Sprintf("%d", key)
value, exists := t.tree.Get(strKey)

if !exists {
return nil, false
}

if tv, ok := value.(TreeValue); ok {
return tv.value, true
}

return nil, false
}

// BinaryLogTree manages binary log constants
type BinaryLogTree struct {
tree *avl.Tree
}

// NewBinaryLogTree initializes a new BinaryLogTree
func NewBinaryLogTree() *BinaryLogTree {
tree := avl.NewTree()

logs := [8]string{
"0",
"3",
"15",
"255",
"65535",
"4294967295",
"18446744073709551615",
"340282366920938463463374607431768211455",
}

for i, value := range logs {
key := ufmt.Sprintf("%d", i)
tree.Set(key, TreeValue{u256.MustFromDecimal(value)})
}

return &BinaryLogTree{tree}
}

// GetLog retrieves the binary log constant at given index
func (t *BinaryLogTree) GetLog(idx int) (*u256.Uint, bool) {
strKey := ufmt.Sprintf("%d", idx)
value, exists := t.tree.Get(strKey)

if !exists {
return nil, false
}

if tv, ok := value.(TreeValue); ok {
return tv.value, true
}

return nil, false
}

// TickMathGetSqrtRatioAtTick calculates the square root price ratio for a given tick.
//
// This function computes the square root ratio (sqrt(price)) at a specific tick,
Expand Down Expand Up @@ -100,20 +181,23 @@ func TickMathGetSqrtRatioAtTick(tick int32) *u256.Uint { // uint160 sqrtPriceX96

ratio := u256.MustFromDecimal("340282366920938463463374607431768211456") // consts.Q128
initialBit := int32(0x1)
if val, exists := tickRatioMap[initialBit]; (absTick&initialBit) != 0 && exists {

if val, exists := tickRatioTree.GetRatio(initialBit); exists && (absTick&initialBit) != 0 {
ratio = val
}

for mask, value := range tickRatioMap {
if mask == initialBit {
continue
calculateRatio := func(mask int32) *u256.Uint {
if value, exists := tickRatioTree.GetRatio(mask); exists && absTick&mask != 0 {
return new(u256.Uint).Rsh(
new(u256.Uint).Mul(ratio, value),
128,
)
}
return ratio
}

if absTick&mask != 0 {
// ratio = (ratio * value) >> 128
ratio = new(u256.Uint).Mul(ratio, value)
ratio = ratio.Rsh(ratio, 128)
}
for mask := int32(0x2); mask <= 0x80000; mask *= 2 {
ratio = calculateRatio(mask)
}

if tick > 0 {
Expand Down Expand Up @@ -143,7 +227,7 @@ func TickMathGetTickAtSqrtRatio(sqrtPriceX96 *u256.Uint) int32 {
if !(cond1 && cond2) {
panic(newErrorWithDetail(
errOutOfRange,
ufmt.Sprintf("tick_math.gno__TickMathGetTickAtSqrtRatio() || sqrtPriceX96 is out of range, sqrtPriceX96: %s", sqrtPriceX96.ToString()),
ufmt.Sprintf("sqrtPriceX96 is out of range, sqrtPriceX96: %s", sqrtPriceX96.ToString()),
))
}

Expand All @@ -162,10 +246,17 @@ func TickMathGetTickAtSqrtRatio(sqrtPriceX96 *u256.Uint) int32 {
func findMSB(ratio *u256.Uint) (*u256.Uint, *u256.Uint) {
msb := u256.Zero()

calculateMSB := func(i int) (*u256.Uint, *u256.Uint) {
if logConst, exists := binaryLogTree.GetLog(i); exists {
f := new(u256.Uint).Lsh(gt(ratio, logConst), uint(i))
msb = new(u256.Uint).Or(msb, f)
ratio = new(u256.Uint).Rsh(ratio, uint(f.Uint64()))
}
return msb, ratio
}

for i := 7; i >= 1; i-- {
f := new(u256.Uint).Lsh(gt(ratio, binaryLogConsts[i]), uint(i))
msb = new(u256.Uint).Or(msb, f)
ratio = new(u256.Uint).Rsh(ratio, uint(f.Uint64()))
msb, ratio = calculateMSB(i)
}

// handle the remaining bits
Expand Down

0 comments on commit 0b3e850

Please sign in to comment.