Skip to content

Commit

Permalink
refactor: Overflow check for type conversion to int256 in delta amoun…
Browse files Browse the repository at this point in the history
…t calculation
  • Loading branch information
onlyhyde committed Dec 15, 2024
1 parent 6f3bfde commit 19eb3be
Show file tree
Hide file tree
Showing 3 changed files with 109 additions and 7 deletions.
1 change: 1 addition & 0 deletions _deploy/p/gnoswap/pool/consts.gno
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ const (
MAX_UINT128 string = "340282366920938463463374607431768211455"
MAX_UINT160 string = "1461501637330902918203684832716283019655932542975"
MAX_UINT256 string = "115792089237316195423570985008687907853269984665640564039457584007913129639935"
MAX_INT256 string = "57896044618658097711785492504343953926634992332820282019728792003956564819967"

Q64 string = "18446744073709551616" // 2 ** 64
Q96 string = "79228162514264337593543950336" // 2 ** 96
Expand Down
33 changes: 26 additions & 7 deletions _deploy/p/gnoswap/pool/sqrt_price_math.gno
Original file line number Diff line number Diff line change
Expand Up @@ -325,7 +325,10 @@ func sqrtPriceMathGetAmount1DeltaHelper(
//
// Notes:
// - This function relies on the helper function `sqrtPriceMathGetAmount0DeltaHelper` to perform the core calculation.
// - The rounding behavior of the result is controlled by the `roundUp` parameter passed to the helper function:
// - The helper function calculates the absolute difference between token0 amounts within the range.
// - If the computed result exceeds the maximum allowable value for int256 (2**255 - 1), the function will panic
// with an appropriate overflow error.
// - The rounding behavior of the result is controlled by the `roundUp` parameter passed to the helper function:
// - For negative liquidity, rounding is always down.
// - For positive liquidity, rounding is always up.
func SqrtPriceMathGetAmount0DeltaStr(
Expand All @@ -335,12 +338,20 @@ func SqrtPriceMathGetAmount0DeltaStr(
) string {
if liquidity.IsNeg() {
u := sqrtPriceMathGetAmount0DeltaHelper(sqrtRatioAX96, sqrtRatioBX96, liquidity.Abs(), false)
if u.Gt(u256.MustFromDecimal(MAX_INT256)) {
// if u > (2**255 - 1), cannot cast to int256
panic("SqrtPriceMathGetAmount0DeltaStr: overflow")
}
i := i256.FromUint256(u)
return i256.Zero().Neg(i).ToString()
} else {
u := sqrtPriceMathGetAmount0DeltaHelper(sqrtRatioAX96, sqrtRatioBX96, liquidity.Abs(), true)
if u.Gt(u256.MustFromDecimal(MAX_INT256)) {
// if u > (2**255 - 1), cannot cast to int256
panic("SqrtPriceMathGetAmount0DeltaStr: overflow")
}
return i256.FromUint256(u).ToString()
}

u := sqrtPriceMathGetAmount0DeltaHelper(sqrtRatioAX96, sqrtRatioBX96, liquidity.Abs(), true)
return i256.FromUint256(u).ToString()
}

// SqrtPriceMathGetAmount1DeltaStr calculates the difference in the amount of token1
Expand Down Expand Up @@ -370,10 +381,18 @@ func SqrtPriceMathGetAmount1DeltaStr(
) string {
if liquidity.IsNeg() {
u := sqrtPriceMathGetAmount1DeltaHelper(sqrtRatioAX96, sqrtRatioBX96, liquidity.Abs(), false)
if u.Gt(u256.MustFromDecimal(MAX_INT256)) {
// if u > (2**255 - 1), cannot cast to int256
panic("SqrtPriceMathGetAmount1DeltaStr: overflow")
}
i := i256.FromUint256(u)
return i256.Zero().Neg(i).ToString()
} else {
u := sqrtPriceMathGetAmount1DeltaHelper(sqrtRatioAX96, sqrtRatioBX96, liquidity.Abs(), true)
if u.Gt(u256.MustFromDecimal(MAX_INT256)) {
// if u > (2**255 - 1), cannot cast to int256
panic("SqrtPriceMathGetAmount1DeltaStr: overflow")
}
return i256.FromUint256(u).ToString()
}

u := sqrtPriceMathGetAmount1DeltaHelper(sqrtRatioAX96, sqrtRatioBX96, liquidity.Abs(), true)
return i256.FromUint256(u).ToString()
}
82 changes: 82 additions & 0 deletions _deploy/p/gnoswap/pool/sqrt_price_math_test.gno
Original file line number Diff line number Diff line change
Expand Up @@ -88,6 +88,41 @@ func TestSqrtPriceMathGetAmount0DeltaStr(t *testing.T) {
t.Error("Result should be negative for negative liquidity")
}
})

t.Run("panic overflow when getting amount0 with positive liquidity", func(t *testing.T) {
defer func() {
if r := recover(); r == nil {
t.Error("Expected panic for overflow amount0")
} else {
uassert.Equal(t, "SqrtPriceMathGetAmount0DeltaStr: overflow", r)
}
}()

// Inputs to trigger panic
sqrtRatioAX96 := u256.MustFromDecimal("1") // very low value
sqrtRatioBX96 := u256.MustFromDecimal("340282366920938463463374607431768211455") // very high value(2^128-1)
liquidity := i256.FromUint256(u256.MustFromDecimal("115792089237316195423570985008687907853269984665640564039457584007913129639935"))

SqrtPriceMathGetAmount0DeltaStr(sqrtRatioAX96, sqrtRatioBX96, liquidity)
})

t.Run("panic overflow when getting amount0 with negative liquidity", func(t *testing.T) {
defer func() {
if r := recover(); r == nil {
t.Error("Expected panic for overflow amount0")
} else {
uassert.Equal(t, "SqrtPriceMathGetAmount0DeltaStr: overflow", r)
}
}()

// Inputs to trigger panic
sqrtRatioAX96 := u256.MustFromDecimal("1") // very low value
sqrtRatioBX96 := u256.MustFromDecimal("340282366920938463463374607431768211455") // very high value(2^128-1)
liquidity := i256.FromUint256(u256.MustFromDecimal("115792089237316195423570985008687907853269984665640564039457584007913129639935"))
liquidity = liquidity.Neg(liquidity) // Make liquidity negative

SqrtPriceMathGetAmount0DeltaStr(sqrtRatioAX96, sqrtRatioBX96, liquidity)
})
}

func TestSqrtPriceMathGetAmount1DeltaStr(t *testing.T) {
Expand All @@ -102,6 +137,53 @@ func TestSqrtPriceMathGetAmount1DeltaStr(t *testing.T) {
t.Error("Result should be positive for positive liquidity")
}
})

t.Run("negative liquidity", func(t *testing.T) {
ratioA := u256.MustFromDecimal("1000000")
ratioB := u256.MustFromDecimal("2000000")
liquidity := i256.Zero().Neg(i256.FromUint256(u256.MustFromDecimal("5000000")))

result := SqrtPriceMathGetAmount0DeltaStr(ratioA, ratioB, liquidity)

if result[0] != '-' {
t.Error("Result should be negative for negative liquidity")
}
})

t.Run("panic overflow when getting amount1 with positive liquidity", func(t *testing.T) {
defer func() {
if r := recover(); r == nil {
t.Error("Expected panic for overflow amount1")
} else {
uassert.Equal(t, "SqrtPriceMathGetAmount1DeltaStr: overflow", r)
}
}()

// Inputs to trigger panic
sqrtRatioAX96 := u256.MustFromDecimal("1") // very low value
sqrtRatioBX96 := u256.MustFromDecimal("79228162514264337593543950335") // slightly below Q96
liquidity := i256.FromUint256(u256.MustFromDecimal("115792089237316195423570985008687907853269984665640564039457584007913129639935"))

SqrtPriceMathGetAmount1DeltaStr(sqrtRatioAX96, sqrtRatioBX96, liquidity)
})

t.Run("panic overflow when getting amount1 with negative liquidity", func(t *testing.T) {
defer func() {
if r := recover(); r == nil {
t.Error("Expected panic for overflow amount1")
} else {
uassert.Equal(t, "SqrtPriceMathGetAmount1DeltaStr: overflow", r)
}
}()

// Inputs to trigger panic
sqrtRatioAX96 := u256.MustFromDecimal("1") // very low value
sqrtRatioBX96 := u256.MustFromDecimal("79228162514264337593543950335") // slightly below Q96
liquidity := i256.FromUint256(u256.MustFromDecimal("115792089237316195423570985008687907853269984665640564039457584007913129639935"))
liquidity = liquidity.Neg(liquidity) // Make liquidity negative

SqrtPriceMathGetAmount1DeltaStr(sqrtRatioAX96, sqrtRatioBX96, liquidity)
})
}

func TestSqrtPriceMathGetNextSqrtPriceFromInput(t *testing.T) {
Expand Down

0 comments on commit 19eb3be

Please sign in to comment.