Skip to content

Commit e6e0a0f

Browse files
authored
Merge branch 'main' into refactor/gsw-2083
2 parents b3333d4 + fd7a860 commit e6e0a0f

File tree

9 files changed

+333
-378
lines changed

9 files changed

+333
-378
lines changed

Diff for: contract/p/gnoswap/gnsmath/bit_math.gno

+14-13
Original file line numberDiff line numberDiff line change
@@ -1,27 +1,28 @@
11
package gnsmath
22

33
import (
4+
"gno.land/p/gnoswap/consts"
45
u256 "gno.land/p/gnoswap/uint256"
56
)
67

78
var (
89
msbShifts = []bitShift{
9-
{u256.MustFromDecimal(Q128), 128}, // 2^128
10-
{u256.MustFromDecimal(Q64), 64}, // 2^64
11-
{u256.NewUint(0x100000000), 32}, // 2^32
12-
{u256.NewUint(0x10000), 16}, // 2^16
13-
{u256.NewUint(0x100), 8}, // 2^8
14-
{u256.NewUint(0x10), 4}, // 2^4
15-
{u256.NewUint(0x4), 2}, // 2^2
16-
{u256.NewUint(0x2), 1}, // 2^1
10+
{u256.MustFromDecimal(consts.Q128), 128}, // 2^128
11+
{u256.MustFromDecimal(consts.Q64), 64}, // 2^64
12+
{u256.NewUint(0x100000000), 32}, // 2^32
13+
{u256.NewUint(0x10000), 16}, // 2^16
14+
{u256.NewUint(0x100), 8}, // 2^8
15+
{u256.NewUint(0x10), 4}, // 2^4
16+
{u256.NewUint(0x4), 2}, // 2^2
17+
{u256.NewUint(0x2), 1}, // 2^1
1718
}
1819

1920
lsbShifts = []bitShift{
20-
{u256.MustFromDecimal(MAX_UINT128), 128},
21-
{u256.MustFromDecimal(MAX_UINT64), 64},
22-
{u256.MustFromDecimal(MAX_UINT32), 32},
23-
{u256.MustFromDecimal(MAX_UINT16), 16},
24-
{u256.MustFromDecimal(MAX_UINT8), 8},
21+
{u256.MustFromDecimal(consts.MAX_UINT128), 128},
22+
{u256.MustFromDecimal(consts.MAX_UINT64), 64},
23+
{u256.MustFromDecimal(consts.MAX_UINT32), 32},
24+
{u256.MustFromDecimal(consts.MAX_UINT16), 16},
25+
{u256.MustFromDecimal(consts.MAX_UINT8), 8},
2526
{u256.NewUint(0xf), 4},
2627
{u256.NewUint(0x3), 2},
2728
{u256.NewUint(0x1), 1},

Diff for: contract/p/gnoswap/gnsmath/consts.gno

-16
This file was deleted.

Diff for: contract/p/gnoswap/gnsmath/sqrt_price_math.gno

+46-27
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
package gnsmath
22

33
import (
4+
"gno.land/p/gnoswap/consts"
45
i256 "gno.land/p/gnoswap/int256"
56
u256 "gno.land/p/gnoswap/uint256"
67
)
@@ -11,47 +12,60 @@ const (
1112
)
1213

1314
var (
14-
q96 = u256.MustFromDecimal(Q96)
15-
max160 = u256.MustFromDecimal(MAX_UINT160)
15+
q96 = u256.MustFromDecimal(consts.Q96)
16+
max160 = u256.MustFromDecimal(consts.MAX_UINT160)
1617
)
1718

1819
// getNextPriceAmount0Add calculates the next sqrt price when we are adding token0.
1920
// Preserves the rounding-up logic. No in-place mutation of input arguments.
2021
func getNextPriceAmount0Add(
21-
sqrtPX96, liquidity, amount *u256.Uint,
22+
currentSqrtPriceX96, liquidity, amountToAdd *u256.Uint,
2223
) *u256.Uint {
23-
numerator1 := new(u256.Uint).Lsh(liquidity, Q96_RESOLUTION)
24-
product := new(u256.Uint).Mul(amount, sqrtPX96)
25-
26-
// overflow check
27-
if new(u256.Uint).Div(product, amount).Eq(sqrtPX96) {
28-
denominator := new(u256.Uint).Add(numerator1, product)
29-
if denominator.Gte(numerator1) {
30-
return u256.MulDivRoundingUp(numerator1, sqrtPX96, denominator)
24+
// Shift liquidity left by Q96 bits to increase precision
25+
liquidityShifted := new(u256.Uint).Lsh(liquidity, Q96_RESOLUTION)
26+
// Multiply the amount to add by the current square root price
27+
amountTimesSqrtPrice := new(u256.Uint).Mul(amountToAdd, currentSqrtPriceX96)
28+
29+
// Overflow check: Ensure (amountTimesSqrtPrice / amountToAdd) == currentSqrtPriceX96
30+
if new(u256.Uint).Div(amountTimesSqrtPrice, amountToAdd).Eq(currentSqrtPriceX96) {
31+
// Compute denominator: liquidityShifted + (amountToAdd * currentSqrtPriceX96)
32+
denominator := new(u256.Uint).Add(liquidityShifted, amountTimesSqrtPrice)
33+
if denominator.Gte(liquidityShifted) {
34+
return u256.MulDivRoundingUp(liquidityShifted, currentSqrtPriceX96, denominator)
3135
}
3236
}
3337

34-
divValue := new(u256.Uint).Div(numerator1, sqrtPX96)
35-
addValue := new(u256.Uint).Add(divValue, amount)
38+
// Alternative computation path: (liquidityShifted / currentSqrtPriceX96) + amountToAdd
39+
divValue := new(u256.Uint).Div(liquidityShifted, currentSqrtPriceX96)
40+
addValue := new(u256.Uint).Add(divValue, amountToAdd)
3641

37-
return u256.DivRoundingUp(numerator1, addValue)
42+
// Compute the next square root price using division rounding up
43+
return u256.DivRoundingUp(liquidityShifted, addValue)
3844
}
3945

4046
// getNextPriceAmount0Remove calculates the next sqrt price when we are removing token0.
4147
// Preserves the rounding-up logic. No in-place mutation of input arguments.
4248
func getNextPriceAmount0Remove(
43-
sqrtPX96, liquidity, amount *u256.Uint,
49+
currentSqrtPriceX96, liquidity, amountToRemove *u256.Uint,
4450
) *u256.Uint {
45-
numerator1 := new(u256.Uint).Lsh(liquidity, Q96_RESOLUTION)
46-
product := new(u256.Uint).Mul(amount, sqrtPX96)
51+
// Shift liquidity left by Q96 bits to increase precision
52+
liquidityShifted := new(u256.Uint).Lsh(liquidity, Q96_RESOLUTION)
53+
54+
// Multiply the amount to remove by the current square root price
55+
amountTimesSqrtPrice := new(u256.Uint).Mul(amountToRemove, currentSqrtPriceX96)
4756

4857
// Conditions must hold: product/amount == sqrtPX96 and numerator1 > product
49-
if !new(u256.Uint).Div(product, amount).Eq(sqrtPX96) || !numerator1.Gt(product) {
58+
if !new(u256.Uint).Div(amountTimesSqrtPrice, amountToRemove).Eq(currentSqrtPriceX96) ||
59+
!liquidityShifted.Gt(amountTimesSqrtPrice) {
5060
panic(errInvalidPoolSqrtPrice)
5161
}
5262

53-
denominator := new(u256.Uint).Sub(numerator1, product)
54-
nextSqrtPrice := u256.MulDivRoundingUp(numerator1, sqrtPX96, denominator)
63+
// Compute denominator: liquidityShifted - (amountToRemove * currentSqrtPriceX96)
64+
denominator := new(u256.Uint).Sub(liquidityShifted, amountTimesSqrtPrice)
65+
// Calculate next square root price: (liquidityShifted * currentSqrtPriceX96) / denominator (with rounding up)
66+
nextSqrtPrice := u256.MulDivRoundingUp(liquidityShifted, currentSqrtPriceX96, denominator)
67+
68+
// Check for overflow
5569
if nextSqrtPrice.Gt(max160) {
5670
panic(errNextSqrtPriceOverflow)
5771
}
@@ -95,11 +109,9 @@ func getNextSqrtPriceFromAmount0RoundingUp(
95109
if add {
96110
return getNextPriceAmount0Add(sqrtPX96, liquidity, amount)
97111
}
98-
99112
return getNextPriceAmount0Remove(sqrtPX96, liquidity, amount)
100113
}
101114

102-
103115
// getNextPriceAmount1Add calculates the next sqrt price when adding token1.
104116
// Preserves rounding-down logic for the final result.
105117
func getNextPriceAmount1Add(
@@ -172,9 +184,16 @@ func getNextPriceAmount1Remove(
172184
// - The function uses high-precision math (MulDiv and DivRoundingUp) to handle division and prevent precision loss.
173185
// - The function validates input conditions and panics if the state is invalid.
174186
func getNextSqrtPriceFromAmount1RoundingDown(
175-
sqrtPX96, liquidity, amount *u256.Uint,
187+
sqrtPX96,
188+
liquidity,
189+
amount *u256.Uint,
176190
add bool,
177191
) *u256.Uint {
192+
// Shortcut: if no amount, return original price
193+
if amount.IsZero() {
194+
return sqrtPX96
195+
}
196+
178197
if add {
179198
return getNextPriceAmount1Add(sqrtPX96, liquidity, amount)
180199
}
@@ -367,7 +386,7 @@ func GetAmount0DeltaStr(
367386
) string {
368387
if liquidity.IsNeg() {
369388
u := getAmount0DeltaHelper(sqrtRatioAX96, sqrtRatioBX96, liquidity.Abs(), false)
370-
if u.Gt(u256.MustFromDecimal(MAX_INT256)) {
389+
if u.Gt(u256.MustFromDecimal(consts.MAX_INT256)) {
371390
// if u > (2**255 - 1), cannot cast to int256
372391
panic(errAmount0DeltaOverflow)
373392
}
@@ -376,7 +395,7 @@ func GetAmount0DeltaStr(
376395
}
377396

378397
u := getAmount0DeltaHelper(sqrtRatioAX96, sqrtRatioBX96, liquidity.Abs(), true)
379-
if u.Gt(u256.MustFromDecimal(MAX_INT256)) {
398+
if u.Gt(u256.MustFromDecimal(consts.MAX_INT256)) {
380399
// if u > (2**255 - 1), cannot cast to int256
381400
panic(errAmount0DeltaOverflow)
382401
}
@@ -410,7 +429,7 @@ func GetAmount1DeltaStr(
410429
) string {
411430
if liquidity.IsNeg() {
412431
u := getAmount1DeltaHelper(sqrtRatioAX96, sqrtRatioBX96, liquidity.Abs(), false)
413-
if u.Gt(u256.MustFromDecimal(MAX_INT256)) {
432+
if u.Gt(u256.MustFromDecimal(consts.MAX_INT256)) {
414433
// if u > (2**255 - 1), cannot cast to int256
415434
panic(errAmount1DeltaOverflow)
416435
}
@@ -419,7 +438,7 @@ func GetAmount1DeltaStr(
419438
}
420439

421440
u := getAmount1DeltaHelper(sqrtRatioAX96, sqrtRatioBX96, liquidity.Abs(), true)
422-
if u.Gt(u256.MustFromDecimal(MAX_INT256)) {
441+
if u.Gt(u256.MustFromDecimal(consts.MAX_INT256)) {
423442
// if u > (2**255 - 1), cannot cast to int256
424443
panic(errAmount1DeltaOverflow)
425444
}

Diff for: contract/p/gnoswap/gnsmath/sqrt_price_math_test.gno

+3-2
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@ import (
55

66
"gno.land/p/demo/uassert"
77

8+
"gno.land/p/gnoswap/consts"
89
i256 "gno.land/p/gnoswap/int256"
910
u256 "gno.land/p/gnoswap/uint256"
1011
)
@@ -422,15 +423,15 @@ func TestSqrtPriceMathGetNextSqrtPriceFromOutput(t *testing.T) {
422423
name: "reverts if amountOut is impossible in zero for one direction",
423424
sqrtPriceX96: encodePriceSqrt("1", "1"),
424425
liquidity: u256.NewUint(1),
425-
amountOut: u256.MustFromDecimal(MAX_UINT256),
426+
amountOut: u256.MustFromDecimal(consts.MAX_UINT256),
426427
zeroForOne: true,
427428
shouldPanic: true,
428429
},
429430
{
430431
name: "reverts if amountOut is impossible in one for zero direction",
431432
sqrtPriceX96: encodePriceSqrt("1", "1"),
432433
liquidity: u256.NewUint(1),
433-
amountOut: u256.MustFromDecimal(MAX_UINT256),
434+
amountOut: u256.MustFromDecimal(consts.MAX_UINT256),
434435
zeroForOne: false,
435436
shouldPanic: true,
436437
},

Diff for: contract/p/gnoswap/int256/gno.mod

-1
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,2 @@
11
module gno.land/p/gnoswap/int256
22

3-
require gno.land/p/gnoswap/uint256 v0.0.0-latest

Diff for: contract/p/gnoswap/uint256/gno.mod

-1
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,2 @@
11
module gno.land/p/gnoswap/uint256
22

3-
require gno.land/p/demo/ufmt v0.0.0-latest

0 commit comments

Comments
 (0)