Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

GSW-1045 #2: fix test cases + rounding error #216

Merged
merged 4 commits into from
May 3, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
15 changes: 8 additions & 7 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ Clone the `gno` repository from `gnoswap-labs`. And switch to the `master_202404
$ cd $WORKDIR
$ git clone https://github.com/gnoswap-labs/gno.git gno
$ cd gno
$ git checkout master_20240401
$ git checkout master_gs
$ make install
```

Expand All @@ -42,17 +42,17 @@ To run unit tests, follow these steps:

```
# copy grc20 tokens
$ cp -R __local/grc20_tokens/* $WORK_DIR/gno/examples/gno.land/r/demo
$ cp -R _deploy/r/demo/* $WORK_DIR/gno/examples/gno.land/r/demo
$ cp -R __local/grc20_tokens/* $WORKDIR/gno/examples/gno.land/r/demo
$ cp -R _deploy/r/demo/* $WORKDIR/gno/examples/gno.land/r/demo

# copy gnoswap base packages ( includes uint256, int256 and bit of pool calculation )
$ cp -R _deploy/p/demo/gnoswap $WORK_DIR/gno/examples/gno.land/p/demo
$ cp -R _deploy/p/demo/gnoswap $WORKDIR/gno/examples/gno.land/p/demo

# copy gnoswap base realms ( includes common logic, variables and consts )
$ cp -R _deploy/r/gnoswap $WORK_DIR/gno/examples/gno.land/r/gnoswap
$ cp -R _deploy/r/demo/gnoswap $WORKDIR/gno/examples/gno.land/r/demo/gnoswap

# copy gnoswap realms
$ cp -R gov pool position router staker $WORK_DIR/gno/examples/gno.land/r/demo
$ cp -R gov pool position router staker $WORKDIR/gno/examples/gno.land/r/demo
```

3. Move all test cases into its own directory:
Expand Down Expand Up @@ -82,7 +82,8 @@ To run unit tests, follow these steps:
### Run the Test Cases

```
$ gno test -root-dir $WORKDIR/gno-for-swap -verbose=true $WORKDIR/gno/examples/gno.land/r/demo/{CONTRACT_FOLDER_HERE}
$ cd $WORKDIR
$ gno test -root-dir $WORKDIR/gno -v=true $WORKDIR/gno/examples/gno.land/r/demo/{CONTRACT_FOLDER_HERE}
```

## Integration Tests
Expand Down
202 changes: 102 additions & 100 deletions __local/test/test_data.mk

Large diffs are not rendered by default.

169 changes: 85 additions & 84 deletions _deploy/p/demo/gnoswap/pool/sqrt_price_math.gno
Original file line number Diff line number Diff line change
Expand Up @@ -3,8 +3,81 @@ package pool
import (
i256 "gno.land/p/demo/gnoswap/int256"
u256 "gno.land/p/demo/gnoswap/uint256"

"gno.land/r/demo/gnoswap/consts"
)

func sqrtPriceMathGetNextSqrtPriceFromAmount0RoundingUp(
sqrtPX96 *u256.Uint, // uint160
liquidity *u256.Uint, // uint128
amount *u256.Uint, // uint256
add bool,
) *u256.Uint { // uint160
if amount.IsZero() {
return sqrtPX96
}

numerator1 := new(u256.Uint).Lsh(liquidity, 96)
product := new(u256.Uint).Mul(amount, sqrtPX96)

if add {
if new(u256.Uint).Div(product, amount).Eq(sqrtPX96) {
denominator := new(u256.Uint).Add(numerator1, product)

if denominator.Gte(numerator1) {
return u256.MulDivRoundingUp(numerator1, sqrtPX96, denominator)
}
}

div := new(u256.Uint).Div(numerator1, sqrtPX96)
add := new(u256.Uint).Add(div, amount)
return u256.DivRoundingUp(numerator1, add)
} else {
cond1 := new(u256.Uint).Div(product, amount).Eq(sqrtPX96)
cond2 := numerator1.Gt(product)

if !(cond1 && cond2) {
panic("pool_sqrt price math #1")
}

denominator := new(u256.Uint).Sub(numerator1, product)
return u256.MulDivRoundingUp(numerator1, sqrtPX96, denominator)
}
}

func sqrtPriceMathGetNextSqrtPriceFromAmount1RoundingDown(
sqrtPX96 *u256.Uint, // uint160
liquidity *u256.Uint, // uint1288
amount *u256.Uint, // uint256
add bool,
) *u256.Uint { // uint160
quotient := u256.Zero()

if add {
if amount.Lte(u256.MustFromDecimal(MAX_UINT160)) {
value1 := new(u256.Uint).Lsh(amount, 96)
quotient = new(u256.Uint).Div(value1, liquidity)
} else {
quotient = u256.MulDiv(amount, u256.MustFromDecimal(consts.Q96), liquidity)
}

return new(u256.Uint).Add(sqrtPX96, quotient)
} else {
if amount.Lte(u256.MustFromDecimal(MAX_UINT160)) {
value1 := new(u256.Uint).Lsh(amount, 96)
quotient = u256.DivRoundingUp(value1, liquidity)
} else {
quotient = u256.MulDivRoundingUp(amount, u256.MustFromDecimal(consts.Q96), liquidity)
}

if !(sqrtPX96.Gt(quotient)) {
panic("pool_sqrt price math #2")
}

return new(u256.Uint).Sub(sqrtPX96, quotient)
}
}

func sqrtPriceMathGetNextSqrtPriceFromInput(
sqrtPX96 *u256.Uint, // uint160
liquidity *u256.Uint, // uint128
Expand Down Expand Up @@ -40,18 +113,21 @@ func sqrtPriceMathGetAmount0DeltaHelper(
sqrtRatioAX96, sqrtRatioBX96 = sqrtRatioBX96, sqrtRatioAX96
}

numerator1 := new(u256.Uint).Lsh(liquidity, 96)
numerator2 := new(u256.Uint).Sub(sqrtRatioBX96, sqrtRatioAX96)

if !(sqrtRatioAX96.Gt(u256.Zero())) {
panic("pool_sqrt price math #3")
}

numerator1 := new(u256.Uint).Lsh(liquidity, 96)
numerator2 := new(u256.Uint).Sub(sqrtRatioBX96, sqrtRatioAX96)
value := u256.MulDiv(numerator1, numerator2, sqrtRatioBX96)

if roundUp {
return u256.DivRoundingUp(value, sqrtRatioAX96)
value1 := u256.MulDivRoundingUp(numerator1, numerator2, sqrtRatioBX96)
return u256.DivRoundingUp(value1, sqrtRatioAX96)
} else {
return new(u256.Uint).Div(value, sqrtRatioAX96)
value1 := u256.MulDiv(numerator1, numerator2, sqrtRatioBX96)
return new(u256.Uint).Div(value1, sqrtRatioAX96)
}
}

Expand All @@ -65,12 +141,12 @@ func sqrtPriceMathGetAmount1DeltaHelper(
sqrtRatioAX96, sqrtRatioBX96 = sqrtRatioBX96, sqrtRatioAX96
}

value := new(u256.Uint).Sub(sqrtRatioBX96, sqrtRatioAX96)

if roundUp {
return u256.MulDiv(liquidity, value, u256.MustFromDecimal(Q96))
diff := new(u256.Uint).Sub(sqrtRatioBX96, sqrtRatioAX96)
return u256.MulDivRoundingUp(liquidity, diff, u256.MustFromDecimal(consts.Q96))
} else {
return u256.MulDiv(liquidity, value, u256.MustFromDecimal(Q96))
diff := new(u256.Uint).Sub(sqrtRatioBX96, sqrtRatioAX96)
return u256.MulDiv(liquidity, diff, u256.MustFromDecimal(consts.Q96))
}
}

Expand All @@ -79,12 +155,12 @@ func SqrtPriceMathGetAmount0DeltaStr(
sqrtRatioBX96 *u256.Uint, // uint160
liquidity *i256.Int, // int128
) string { // int256

if liquidity.IsNeg() {
u := sqrtPriceMathGetAmount0DeltaHelper(sqrtRatioAX96, sqrtRatioBX96, liquidity.Abs(), false)
i := i256.FromUint256(u)
return i256.Zero().Neg(i).ToString()
}

u := sqrtPriceMathGetAmount0DeltaHelper(sqrtRatioAX96, sqrtRatioBX96, liquidity.Abs(), true)
return i256.FromUint256(u).ToString()
}
Expand All @@ -103,78 +179,3 @@ func SqrtPriceMathGetAmount1DeltaStr(
u := sqrtPriceMathGetAmount1DeltaHelper(sqrtRatioAX96, sqrtRatioBX96, liquidity.Abs(), true)
return i256.FromUint256(u).ToString()
}

// private
func sqrtPriceMathGetNextSqrtPriceFromAmount0RoundingUp(
sqrtPX96 *u256.Uint, // uint160
liquidity *u256.Uint, // uint128
amount *u256.Uint, // uint256
add bool,
) *u256.Uint { // uint160
if amount.IsZero() {
return sqrtPX96
}

numerator1 := new(u256.Uint).Lsh(liquidity, 96)
product := new(u256.Uint).Mul(amount, sqrtPX96)

if add {
if new(u256.Uint).Div(product, amount).Eq(sqrtPX96) {
denominator := new(u256.Uint).Add(numerator1, product)

if denominator.Gte(numerator1) {
return u256.MulDiv(numerator1, sqrtPX96, denominator)
}
}

_value1 := new(u256.Uint).Div(numerator1, sqrtPX96)
_value2 := new(u256.Uint).Add(_value1, amount)
return u256.DivRoundingUp(numerator1, _value2)
} else {
cond1 := new(u256.Uint).Div(product, amount).Eq(sqrtPX96)
cond2 := numerator1.Gt(product)

if !(cond1 && cond2) {
panic("pool_sqrt price math #1")
}
denominator := new(u256.Uint).Sub(numerator1, product)

return u256.MulDiv(numerator1, sqrtPX96, denominator)
}
}

func sqrtPriceMathGetNextSqrtPriceFromAmount1RoundingDown(
sqrtPX96 *u256.Uint, // uint160
liquidity *u256.Uint, // uint1288
amount *u256.Uint, // uint256
add bool,
) *u256.Uint { // uint160
quotient := u256.Zero()

if !(amount.Lte(u256.MustFromDecimal(MAX_UINT160))) {
quotient = u256.MulDiv(amount, u256.MustFromDecimal(Q96), liquidity)
}

if add {
if amount.Lte(u256.MustFromDecimal(MAX_UINT160)) {
quotient = new(u256.Uint).Lsh(amount, 96)
quotient = new(u256.Uint).Div(quotient, liquidity)
}

quotient = new(u256.Uint).Sub(quotient, u256.One())
return new(u256.Uint).Add(sqrtPX96, quotient)
} else {
if amount.Lte(u256.MustFromDecimal(MAX_UINT160)) {
quotient = new(u256.Uint).Lsh(amount, 96)
quotient = u256.DivRoundingUp(quotient, liquidity)
}

if !(sqrtPX96.Gt(quotient)) {
panic("pool_sqrt price math #2")
}

// roundDown
quotient = new(u256.Uint).Sub(quotient, u256.One())
return new(u256.Uint).Sub(sqrtPX96, quotient)
}
}
11 changes: 2 additions & 9 deletions _deploy/p/demo/gnoswap/pool/swap_math.gno
Original file line number Diff line number Diff line change
Expand Up @@ -24,10 +24,7 @@ func SwapMathComputeSwapStepStr(
feeAmount := u256.Zero()

if exactIn {
amountRemainingLessFee := u256.Zero()
_amountRemaining := amountRemaining.Abs()
amountRemainingLessFee = amountRemainingLessFee.Mul(_amountRemaining, u256.NewUint(1000000-feePips))
amountRemainingLessFee = amountRemainingLessFee.Div(amountRemainingLessFee, u256.NewUint(1000000))
amountRemainingLessFee := u256.MulDiv(amountRemaining.Abs(), u256.NewUint(1000000-feePips), u256.NewUint(1000000))

if isToken1Expensive {
amountIn = sqrtPriceMathGetAmount0DeltaHelper(sqrtRatioTargetX96, sqrtRatioCurrentX96, liquidity, true)
Expand Down Expand Up @@ -100,12 +97,8 @@ func SwapMathComputeSwapStepStr(
if exactIn && !(sqrtRatioNextX96.Eq(sqrtRatioTargetX96)) {
feeAmount = new(u256.Uint).Sub(amountRemaining.Abs(), amountIn)
} else {
feeAmount = new(u256.Uint).Mul(amountIn, u256.NewUint(feePips))
feeAmount = feeAmount.Div(feeAmount, u256.NewUint(1000000-feePips))
feeAmount = u256.MulDivRoundingUp(amountIn, u256.NewUint(feePips), new(u256.Uint).Sub(u256.NewUint(1000000), u256.NewUint(feePips)))
}

if !exactIn && !(amountOut.IsZero()) {
amountOut = amountOut.Add(amountOut, u256.NewUint(1))
}
return sqrtRatioNextX96.ToString(), amountIn.ToString(), amountOut.ToString(), feeAmount.ToString()
}
19 changes: 19 additions & 0 deletions _deploy/p/demo/gnoswap/uint256/gs_overflow_calculation.gno
Original file line number Diff line number Diff line change
Expand Up @@ -126,3 +126,22 @@ func MulDivRoundingUp(

return result
}

// UnsafeMath
// https://github.com/Uniswap/v3-core/blob/d8b1c635c275d2a9450bd6a78f3fa2484fef73eb/contracts/libraries/UnsafeMath.sol
func DivRoundingUp(
x, y *Uint,
) *Uint {
div := new(Uint).Div(x, y)
mod := new(Uint).Mod(x, y)

z := new(Uint).Add(div, gt(mod, Zero()))
return z
}

func gt(x, y *Uint) *Uint {
if x.Gt(y) {
return One()
}
return Zero()
}
25 changes: 0 additions & 25 deletions _deploy/p/demo/gnoswap/uint256/gs_overflow_calculation_test.gno

This file was deleted.

Loading
Loading