Skip to content

Commit

Permalink
Merge pull request #79 from gnoswap-labs/GSW-441-fix-find-best-pool-t…
Browse files Browse the repository at this point in the history
…oken-amount-estimation

GSW-441 fix: `FindBestPool` uses `DrySwap()` to pool path in first condition
  • Loading branch information
harryoh authored Oct 18, 2023
2 parents e4f549d + f7a3400 commit 95d1df9
Show file tree
Hide file tree
Showing 4 changed files with 83 additions and 56 deletions.
File renamed without changes.
Original file line number Diff line number Diff line change
@@ -1,10 +1,11 @@
package pool

import (
"encoding/gjson"
"std"
"testing"

"encoding/gjson"

"gno.land/p/demo/testutils"
"gno.land/r/demo/users"

Expand All @@ -29,23 +30,9 @@ func TestInitManual(t *testing.T) {
}

func TestCreatePool(t *testing.T) {
CreatePool("foo", "bar", uint16(500), 5602223755577321903022134995689) // 85_176 == x4999.904
CreatePool("foo", "bar", uint16(500), 130621891405341611593710811006) // 2.7181459268
CreatePool("foo", "bar", uint16(3000), 130621891405341611593710811006) // 2.7181459268
std.TestSkipHeights(1)
// fee = 500
// tickSpacing = 10

// sqrtPriceX96 = 130621891405341611593710811006
// tick = 10_000
// ratio = 1.648%

CreatePool("foo", "bar", uint16(3000), 255973311431586396528129062412) // 23456 == 3.23%
std.TestSkipHeights(1)
// fee = 3000
// tickSpacing = 60

// sqrtPriceX96 = 255973311431586396528129062412
// tick = 23_456
// ratio = 3.23%
}

func TestPositionMint500(t *testing.T) {
Expand All @@ -54,21 +41,17 @@ func TestPositionMint500(t *testing.T) {
_, _, m0, m1 := pos.Mint(
"foo", // token0
"bar", // token1
uint16(500), // fee 500 ~= tickSpacing 10
84220, // tickLower // x4544
86130, // tickUpper // x5500
30000000, // amount0Desired
30000000, // amount1Desired
uint16(500), // fee 3000 ~= tickSpacing 60
6600, // tickLower
10200, // tickUpper
100, // amount0Desired
100, // amount1Desired
0, // amount0Min
0, // amount1Min
9999999999, // deadline
)

shouldEQ(t, m0, bigint(5987)) // x5010.8565224653
shouldEQ(t, m1, bigint(29999998))

shouldEQ(t, bigint(fooBalance(poolAddr)), m0)
shouldEQ(t, bigint(barBalance(poolAddr)), m1)
shouldEQ(t, m0, bigint(2))
shouldEQ(t, m1, bigint(99))
}

func TestPositionMint3000(t *testing.T) {
Expand All @@ -78,15 +61,15 @@ func TestPositionMint3000(t *testing.T) {
"foo", // token0
"bar", // token1
uint16(3000), // fee 3000 ~= tickSpacing 60
22800, // tickLower
24000, // tickUpper
6600, // tickLower
10200, // tickUpper
1000, // amount0Desired
1000, // amount1Desired
0, // amount0Min
0, // amount1Min
9999999999, // deadline
)
shouldEQ(t, m0, bigint(79))
shouldEQ(t, m0, bigint(23))
shouldEQ(t, m1, bigint(999))
}

Expand All @@ -95,29 +78,42 @@ func TestFindBestPoolTruePositive(t *testing.T) {
"foo", // tokenA
"bar", // tokenB
true, // zeroForOne
500, // amountSpecified
200, // amountSpecified
)
jsonStr := gjson.Parse(bestPoolPathDetail)
shouldEQ(t, jsonStr.Get("response.data.pool_path").String(), "bar_foo_500")
shouldEQ(t, jsonStr.Get("response.data.pool_path").String(), "bar_foo_3000")

// should return empty if not enough balance
{
bestPoolPathDetail := FindBestPool(
"foo", // tokenA
"bar", // tokenB
true, // zeroForOne
438, // amountSpecified
)

jsonStr := gjson.Parse(bestPoolPathDetail)
shouldEQ(t, jsonStr.Get("response.data.pool_path").String(), "")
}
}

func TestFindBestPoolTrueNegative(t *testing.T) {
bestPoolPathDetail := FindBestPool(
"foo", // tokenA
"bar", // tokenB
true, // zeroForOne
-5000, // amountSpecified
-888, // amountSpecified
)
jsonStr := gjson.Parse(bestPoolPathDetail)
shouldEQ(t, jsonStr.Get("response.data.pool_path").String(), "bar_foo_500")
shouldEQ(t, jsonStr.Get("response.data.pool_path").String(), "bar_foo_3000")
}

func TestFindBestPoolFalsePositive(t *testing.T) {
bestPoolPathDetail := FindBestPool(
"foo", // tokenA
"bar", // tokenB
false, // zeroForOne
50, // amountSpecified
5, // amountSpecified
)
jsonStr := gjson.Parse(bestPoolPathDetail)
shouldEQ(t, jsonStr.Get("response.data.pool_path").String(), "bar_foo_3000")
Expand All @@ -128,10 +124,10 @@ func TestFindBestPoolFalseNegative(t *testing.T) {
"foo", // tokenA
"bar", // tokenB
false, // zeroForOne
-1234, // amountSpecified
-11, // amountSpecified
)
jsonStr := gjson.Parse(bestPoolPathDetail)
shouldEQ(t, jsonStr.Get("response.data.pool_path").String(), "bar_foo_500")
shouldEQ(t, jsonStr.Get("response.data.pool_path").String(), "bar_foo_3000")
}

func TestFindBestPoolWrong(t *testing.T) {
Expand Down
4 changes: 2 additions & 2 deletions pool/math_logic.gno
Original file line number Diff line number Diff line change
Expand Up @@ -144,9 +144,9 @@ func DrySwap(
}

if zeroForOne {
require(pool.balances.token1 > amount1, ufmt.Sprintf("[POOL] math_logic.gno__DrySwap()_ZFO_T || pool.balances.token1(%s) > amount1(%s)", pool.balances.token1, amount1))
require(pool.balances.token1 > (-1*amount1), ufmt.Sprintf("[POOL] math_logic.gno__DrySwap()_ZFO_T || pool.balances.token1(%s) > amount1(%s)", pool.balances.token1, (-1*amount1)))
} else {
require(pool.balances.token0 > amount0, ufmt.Sprintf("[POOL] math_logic.gno__DrySwap()_ZFO_F || pool.balances.token0(%s) > amount0(%s)", pool.balances.token0, amount0))
require(pool.balances.token0 > (-1*amount0), ufmt.Sprintf("[POOL] math_logic.gno__DrySwap()_ZFO_F || pool.balances.token0(%s) > amount0(%s)", pool.balances.token0, (-1*amount0)))
}

return amount0, amount1
Expand Down
63 changes: 47 additions & 16 deletions pool/pool_router.gno
Original file line number Diff line number Diff line change
Expand Up @@ -36,34 +36,65 @@ func FindBestPool(
continue
} else if zeroForOne == true && amountSpecified > 0 {
for _, singlePool := range foundPool {
p := GetPoolFromPoolKey(singlePool)
poolSqrtX96 := p.slot0.sqrtPriceX96
poolPrice := poolSqrtX96 * poolSqrtX96 / Q96 / Q96

pool := GetPoolFromPoolKey(singlePool)
if pool.balances.token1 > amountSpecified*poolPrice { // must be bigger (can't be equal due to fee)
firstSelectedPool = append(firstSelectedPool, singlePool)
}
func() {
defer func() {
if r := recover(); r != nil {
continue
}
}()

_, _, fee := poolPathDivide(singlePool)
es0, es1 := DrySwap(
tokenA,
tokenB,
fee,
"",
true,
amountSpecified,
MIN_PRICE,
)

pool := GetPoolFromPoolKey(singlePool)
if pool.balances.token1 > (-1 * es1) { // must be bigger (can't be equal due to fee)
firstSelectedPool = append(firstSelectedPool, singlePool)
}
}()
}

} else if zeroForOne == true && amountSpecified < 0 {
for _, singlePool := range foundPool {
pool := GetPoolFromPoolKey(singlePool)

if pool.balances.token1 > (-1 * amountSpecified) { // must be bigger (can't be equal due to fee)
firstSelectedPool = append(firstSelectedPool, singlePool)
}
}

} else if zeroForOne == false && amountSpecified > 0 {
for _, singlePool := range foundPool {
p := GetPoolFromPoolKey(singlePool)
poolSqrtX96 := p.slot0.sqrtPriceX96
poolPrice := poolSqrtX96 * poolSqrtX96 / Q96 / Q96

pool := GetPoolFromPoolKey(singlePool)
if pool.balances.token0 > amountSpecified/poolPrice { // must be bigger (can't be equal due to fee)
firstSelectedPool = append(firstSelectedPool, singlePool)
}
func() {
defer func() {
if r := recover(); r != nil {
continue
}
}()

_, _, fee := poolPathDivide(singlePool)
es0, es1 := DrySwap(
tokenA,
tokenB,
fee,
"",
false,
amountSpecified,
MAX_PRICE,
)

pool := GetPoolFromPoolKey(singlePool)
if pool.balances.token1 > (-1 * es0) { // must be bigger (can't be equal due to fee)
firstSelectedPool = append(firstSelectedPool, singlePool)
}
}()
}

} else if zeroForOne == false && amountSpecified < 0 {
Expand Down

0 comments on commit 95d1df9

Please sign in to comment.