Skip to content

Commit 1a0d566

Browse files
authored
Merge branch 'main' into refactor-pool
2 parents 9306644 + 66d8f5d commit 1a0d566

File tree

11 files changed

+1135
-144
lines changed

11 files changed

+1135
-144
lines changed

_deploy/p/gnoswap/pool/sqrt_price_math.gno

Lines changed: 4 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -3,8 +3,6 @@ package pool
33
import (
44
i256 "gno.land/p/gnoswap/int256"
55
u256 "gno.land/p/gnoswap/uint256"
6-
7-
"gno.land/r/gnoswap/v1/consts"
86
)
97

108
func sqrtPriceMathGetNextSqrtPriceFromAmount0RoundingUp(
@@ -58,7 +56,7 @@ func sqrtPriceMathGetNextSqrtPriceFromAmount1RoundingDown(
5856
value1 := new(u256.Uint).Lsh(amount, 96)
5957
quotient = new(u256.Uint).Div(value1, liquidity)
6058
} else {
61-
quotient = u256.MulDiv(amount, u256.MustFromDecimal(consts.Q96), liquidity)
59+
quotient = u256.MulDiv(amount, u256.MustFromDecimal(Q96), liquidity)
6260
}
6361

6462
res := new(u256.Uint).Add(sqrtPX96, quotient)
@@ -74,7 +72,7 @@ func sqrtPriceMathGetNextSqrtPriceFromAmount1RoundingDown(
7472
value1 := new(u256.Uint).Lsh(amount, 96)
7573
quotient = u256.DivRoundingUp(value1, liquidity)
7674
} else {
77-
quotient = u256.MulDivRoundingUp(amount, u256.MustFromDecimal(consts.Q96), liquidity)
75+
quotient = u256.MulDivRoundingUp(amount, u256.MustFromDecimal(Q96), liquidity)
7876
}
7977

8078
if !(sqrtPX96.Gt(quotient)) {
@@ -164,10 +162,10 @@ func sqrtPriceMathGetAmount1DeltaHelper(
164162

165163
if roundUp {
166164
diff := new(u256.Uint).Sub(sqrtRatioBX96, sqrtRatioAX96)
167-
return u256.MulDivRoundingUp(liquidity, diff, u256.MustFromDecimal(consts.Q96))
165+
return u256.MulDivRoundingUp(liquidity, diff, u256.MustFromDecimal(Q96))
168166
} else {
169167
diff := new(u256.Uint).Sub(sqrtRatioBX96, sqrtRatioAX96)
170-
return u256.MulDiv(liquidity, diff, u256.MustFromDecimal(consts.Q96))
168+
return u256.MulDiv(liquidity, diff, u256.MustFromDecimal(Q96))
171169
}
172170
}
173171

pool/errors.gno

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -31,7 +31,8 @@ var (
3131
errTransferFailed = errors.New("[GNOSWAP-POOL-021] token transfer failed")
3232
errInvalidTickAndTickSpacing = errors.New("[GNOSWAP-POOL-022] invalid tick and tick spacing requested")
3333
errInvalidAddress = errors.New("[GNOSWAP-POOL-023] invalid address")
34-
errUnderflow = errors.New("[GNOSWAP-POOL-024] underflow") // TODO: make as common error code
34+
errInvalidTickRange = errors.New("[GNOSWAP-POOL-024] tickLower is greater than tickUpper")
35+
errUnderflow = errors.New("[GNOSWAP-POOL-025] underflow") // TODO: make as common error code
3536
)
3637

3738
// addDetailToError adds detail to an error message

pool/pool_manager.gno

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -39,7 +39,7 @@ func (t *tickSpacingMap) Get(fee uint32) int32 {
3939

4040
var (
4141
feeAmountTickSpacing tickSpacingMap = make(tickSpacingMap) // maps fee to tickSpacing || map[feeAmount]tick_spacing
42-
pools poolMap = make(poolMap) // maps poolPath to pool || map[poolPath]*Pool
42+
pools poolMap = make(poolMap) // maps poolPath to pool || map[poolPath]*Pool
4343

4444
slot0FeeProtocol uint8 = 0
4545
)
@@ -69,11 +69,11 @@ func newPoolParams(
6969
price := u256.MustFromDecimal(sqrtPriceX96)
7070
tickSpacing := feeAmountTickSpacing.Get(fee)
7171
return &createPoolParams{
72-
token0Path: token0Path,
73-
token1Path: token1Path,
74-
fee: fee,
72+
token0Path: token0Path,
73+
token1Path: token1Path,
74+
fee: fee,
7575
sqrtPriceX96: price,
76-
tickSpacing: tickSpacing,
76+
tickSpacing: tickSpacing,
7777
}
7878
}
7979

pool/position.gno

Lines changed: 41 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -11,12 +11,30 @@ import (
1111
u256 "gno.land/p/gnoswap/uint256"
1212
)
1313

14+
var (
15+
Q128 = u256.MustFromDecimal(consts.Q128)
16+
)
17+
1418
// positionGetKey generates a unique key for a position based on the owner's address and the tick range.
1519
func positionGetKey(
1620
owner std.Address,
1721
tickLower int32,
1822
tickUpper int32,
1923
) string {
24+
if !owner.IsValid() {
25+
panic(addDetailToError(
26+
errInvalidAddress,
27+
ufmt.Sprintf("position.gno__positionGetKey() || invalid owner address %s", owner.String()),
28+
))
29+
}
30+
31+
if tickLower > tickUpper {
32+
panic(addDetailToError(
33+
errInvalidTickRange,
34+
ufmt.Sprintf("position.gno__positionGetKey() || tickLower(%d) is greater than tickUpper(%d)", tickLower, tickUpper),
35+
))
36+
}
37+
2038
positionKey := ufmt.Sprintf("%s__%d__%d", owner.String(), tickLower, tickUpper)
2139

2240
encoded := base64.StdEncoding.EncodeToString([]byte(positionKey))
@@ -26,11 +44,11 @@ func positionGetKey(
2644
// positionUpdateWithKey updates a position in the pool and returns the updated position.
2745
func (pool *Pool) positionUpdateWithKey(
2846
positionKey string,
29-
liquidityDelta *i256.Int, // int128
30-
feeGrowthInside0X128 *u256.Uint, // uint256
31-
feeGrowthInside1X128 *u256.Uint, // uint256
47+
liquidityDelta *i256.Int,
48+
feeGrowthInside0X128 *u256.Uint,
49+
feeGrowthInside1X128 *u256.Uint,
3250
) PositionInfo {
33-
// PARAM INIT
51+
// if pointer is nil, set to zero for calculation
3452
liquidityDelta = liquidityDelta.NilToZero()
3553
feeGrowthInside0X128 = feeGrowthInside0X128.NilToZero()
3654
feeGrowthInside1X128 = feeGrowthInside1X128.NilToZero()
@@ -44,51 +62,47 @@ func (pool *Pool) positionUpdateWithKey(
4462

4563
// positionUpdate calculates and returns an updated PositionInfo.
4664
func positionUpdate(
47-
self PositionInfo,
48-
liquidityDelta *i256.Int, // int128
49-
feeGrowthInside0X128 *u256.Uint, // uint256
50-
feeGrowthInside1X128 *u256.Uint, // uint256
65+
position PositionInfo,
66+
liquidityDelta *i256.Int,
67+
feeGrowthInside0X128 *u256.Uint,
68+
feeGrowthInside1X128 *u256.Uint,
5169
) PositionInfo {
52-
self.init()
70+
position.init()
5371

5472
var liquidityNext *u256.Uint
5573
if liquidityDelta.IsZero() {
56-
if self.liquidity.IsZero() {
74+
if position.liquidity.IsZero() {
5775
panic(addDetailToError(
5876
errZeroLiquidity,
59-
"position.gno__positionUpdate() || both liquidityDelta and (self)liquidity are zero",
77+
"position.gno__positionUpdate() || both liquidityDelta and current position's liquidity are zero",
6078
))
6179
}
6280

63-
liquidityNext = self.liquidity
81+
liquidityNext = position.liquidity
6482
} else {
65-
liquidityNext = liquidityMathAddDelta(self.liquidity, liquidityDelta)
83+
liquidityNext = liquidityMathAddDelta(position.liquidity, liquidityDelta)
6684
}
6785

6886
tokensOwed0 := u256.Zero()
69-
{
70-
diff := new(u256.Uint).Sub(feeGrowthInside0X128, self.feeGrowthInside0LastX128)
71-
tokensOwed0 = u256.MulDiv(diff, self.liquidity, u256.MustFromDecimal(consts.Q128))
72-
}
87+
diff0 := new(u256.Uint).Sub(feeGrowthInside0X128, position.feeGrowthInside0LastX128)
88+
tokensOwed0 = u256.MulDiv(diff0, position.liquidity, Q128)
7389

7490
tokensOwed1 := u256.Zero()
75-
{
76-
diff := new(u256.Uint).Sub(feeGrowthInside1X128, self.feeGrowthInside1LastX128)
77-
tokensOwed1 = u256.MulDiv(diff, self.liquidity, u256.MustFromDecimal(consts.Q128))
78-
}
91+
diff1 := new(u256.Uint).Sub(feeGrowthInside1X128, position.feeGrowthInside1LastX128)
92+
tokensOwed1 = u256.MulDiv(diff1, position.liquidity, Q128)
7993

8094
if !(liquidityDelta.IsZero()) {
81-
self.liquidity = liquidityNext
95+
position.liquidity = liquidityNext
8296
}
8397

84-
self.feeGrowthInside0LastX128 = feeGrowthInside0X128
85-
self.feeGrowthInside1LastX128 = feeGrowthInside1X128
98+
position.feeGrowthInside0LastX128 = feeGrowthInside0X128
99+
position.feeGrowthInside1LastX128 = feeGrowthInside1X128
86100
if tokensOwed0.Gt(u256.Zero()) || tokensOwed1.Gt(u256.Zero()) {
87-
self.tokensOwed0 = self.tokensOwed0.Add(self.tokensOwed0, tokensOwed0)
88-
self.tokensOwed1 = self.tokensOwed1.Add(self.tokensOwed1, tokensOwed1)
101+
position.tokensOwed0 = position.tokensOwed0.Add(position.tokensOwed0, tokensOwed0)
102+
position.tokensOwed1 = position.tokensOwed1.Add(position.tokensOwed1, tokensOwed1)
89103
}
90104

91-
return self
105+
return position
92106
}
93107

94108
// receiver getters

pool/position_test.gno

Lines changed: 171 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,171 @@
1+
package pool
2+
3+
import (
4+
"std"
5+
"testing"
6+
7+
"gno.land/p/demo/testutils"
8+
"gno.land/p/demo/uassert"
9+
10+
i256 "gno.land/p/gnoswap/int256"
11+
u256 "gno.land/p/gnoswap/uint256"
12+
13+
"gno.land/r/gnoswap/v1/common"
14+
)
15+
16+
func TestPositionGetKey(t *testing.T) {
17+
invalidAddr := std.Address("invalidAddr")
18+
validAddr := testutils.TestAddress("validAddr")
19+
20+
tests := []struct {
21+
owner std.Address
22+
tickLower int32
23+
tickUpper int32
24+
shouldPanic bool
25+
panicMsg string
26+
expectedKey string
27+
}{
28+
{invalidAddr, 100, 200, true, `[GNOSWAP-POOL-023] invalid address || position.gno__positionGetKey() || invalid owner address invalidAddr`, ""}, // invalid address
29+
{validAddr, 200, 100, true, `[GNOSWAP-POOL-024] tickLower is greater than tickUpper || position.gno__positionGetKey() || tickLower(200) is greater than tickUpper(100)`, ""}, // tickLower > tickUpper
30+
{validAddr, -100, -200, true, `[GNOSWAP-POOL-024] tickLower is greater than tickUpper || position.gno__positionGetKey() || tickLower(-100) is greater than tickUpper(-200)`, ""}, // tickLower > tickUpper
31+
{validAddr, 100, 100, false, "", "ZzF3ZXNrYzZ0eWc5anhndWpsdGEwNDdoNmx0YTA0N2g2bGRqbHVkdV9fMTAwX18xMDA="}, // tickLower == tickUpper
32+
{validAddr, 100, 200, false, "", "ZzF3ZXNrYzZ0eWc5anhndWpsdGEwNDdoNmx0YTA0N2g2bGRqbHVkdV9fMTAwX18yMDA="}, // tickLower < tickUpper
33+
}
34+
35+
for _, tc := range tests {
36+
if tc.shouldPanic {
37+
uassert.PanicsWithMessage(t, tc.panicMsg, func() { positionGetKey(tc.owner, tc.tickLower, tc.tickUpper) })
38+
} else {
39+
key := positionGetKey(tc.owner, tc.tickLower, tc.tickUpper)
40+
uassert.Equal(t, tc.expectedKey, key)
41+
}
42+
}
43+
}
44+
45+
func TestPositionUpdateWithKey(t *testing.T) {
46+
var dummyPool *Pool
47+
var positionKey string
48+
49+
t.Run("set up initial data for this test function", func(t *testing.T) {
50+
dummyPool = newPool(
51+
"token0",
52+
"token1",
53+
100,
54+
10,
55+
common.TickMathGetSqrtRatioAtTick(0),
56+
)
57+
58+
positionKey = positionGetKey(
59+
testutils.TestAddress("dummyAddr"),
60+
100,
61+
200,
62+
)
63+
})
64+
65+
tests := []struct {
66+
liquidity *i256.Int
67+
amount0 *u256.Uint
68+
amount1 *u256.Uint
69+
shouldPanic bool
70+
panicMsg string
71+
expectedLiquidity string
72+
}{
73+
{i256.MustFromDecimal("0"), u256.Zero(), u256.Zero(), true, `[GNOSWAP-POOL-010] zero liquidity || position.gno__positionUpdate() || both liquidityDelta and current position's liquidity are zero`, ""},
74+
{i256.MustFromDecimal("100000"), u256.Zero(), u256.Zero(), false, "", "100000"},
75+
}
76+
77+
for _, tc := range tests {
78+
if tc.shouldPanic {
79+
uassert.PanicsWithMessage(t, tc.panicMsg, func() { dummyPool.positionUpdateWithKey(positionKey, tc.liquidity, tc.amount0, tc.amount1) })
80+
} else {
81+
newPos := dummyPool.positionUpdateWithKey(positionKey, tc.liquidity, tc.amount0, tc.amount1)
82+
uassert.Equal(t, newPos.liquidity.ToString(), tc.expectedLiquidity)
83+
}
84+
}
85+
}
86+
87+
func TestPositionUpdate(t *testing.T) {
88+
tests := []struct {
89+
initialLiquidity *u256.Uint
90+
liquidityDelta *i256.Int
91+
feeGrowthInside0X128 *u256.Uint
92+
feeGrowthInside1X128 *u256.Uint
93+
shouldPanic bool
94+
panicMsg string
95+
expectedLiquidity string
96+
expectedFeeGrowthInside0X128 string
97+
expectedFeeGrowthInside1X128 string
98+
expectedToken0Owed string
99+
expectedToken1Owed string
100+
}{
101+
{
102+
initialLiquidity: u256.Zero(),
103+
liquidityDelta: i256.MustFromDecimal("0"),
104+
feeGrowthInside0X128: u256.Zero(),
105+
feeGrowthInside1X128: u256.Zero(),
106+
shouldPanic: true,
107+
panicMsg: `[GNOSWAP-POOL-010] zero liquidity || position.gno__positionUpdate() || both liquidityDelta and current position's liquidity are zero`,
108+
},
109+
{
110+
initialLiquidity: u256.Zero(),
111+
liquidityDelta: i256.MustFromDecimal("100000"),
112+
feeGrowthInside0X128: u256.Zero(),
113+
feeGrowthInside1X128: u256.Zero(),
114+
expectedLiquidity: "100000",
115+
expectedFeeGrowthInside0X128: "0",
116+
expectedFeeGrowthInside1X128: "0",
117+
expectedToken0Owed: "0",
118+
expectedToken1Owed: "0",
119+
},
120+
{
121+
initialLiquidity: u256.Zero(),
122+
liquidityDelta: i256.MustFromDecimal("100000"),
123+
feeGrowthInside0X128: u256.MustFromDecimal("100000000"),
124+
feeGrowthInside1X128: u256.MustFromDecimal("100000000"),
125+
expectedLiquidity: "100000",
126+
expectedFeeGrowthInside0X128: "100000000",
127+
expectedFeeGrowthInside1X128: "100000000",
128+
expectedToken0Owed: "0",
129+
expectedToken1Owed: "0",
130+
},
131+
{
132+
initialLiquidity: u256.NewUint(100000),
133+
liquidityDelta: i256.MustFromDecimal("100000"),
134+
feeGrowthInside0X128: u256.MustFromDecimal("100000000"),
135+
feeGrowthInside1X128: u256.MustFromDecimal("100000000"),
136+
expectedLiquidity: "200000",
137+
expectedFeeGrowthInside0X128: "100000000",
138+
expectedFeeGrowthInside1X128: "100000000",
139+
expectedToken0Owed: "0",
140+
expectedToken1Owed: "0",
141+
},
142+
{
143+
initialLiquidity: u256.MustFromDecimal("340282366920938463463374607431768211456"), // Q128 value
144+
liquidityDelta: i256.Zero(),
145+
feeGrowthInside0X128: u256.MustFromDecimal("100000000"),
146+
feeGrowthInside1X128: u256.MustFromDecimal("200000000"),
147+
expectedLiquidity: "340282366920938463463374607431768211456",
148+
expectedFeeGrowthInside0X128: "100000000",
149+
expectedFeeGrowthInside1X128: "200000000",
150+
expectedToken0Owed: "100000000",
151+
expectedToken1Owed: "200000000",
152+
},
153+
}
154+
155+
for _, tc := range tests {
156+
position := PositionInfo{
157+
liquidity: tc.initialLiquidity,
158+
}
159+
160+
if tc.shouldPanic {
161+
uassert.PanicsWithMessage(t, tc.panicMsg, func() { positionUpdate(position, tc.liquidityDelta, tc.feeGrowthInside0X128, tc.feeGrowthInside1X128) })
162+
} else {
163+
newPos := positionUpdate(position, tc.liquidityDelta, tc.feeGrowthInside0X128, tc.feeGrowthInside1X128)
164+
uassert.Equal(t, newPos.liquidity.ToString(), tc.expectedLiquidity)
165+
uassert.Equal(t, newPos.feeGrowthInside0LastX128.ToString(), tc.expectedFeeGrowthInside0X128)
166+
uassert.Equal(t, newPos.feeGrowthInside1LastX128.ToString(), tc.expectedFeeGrowthInside1X128)
167+
uassert.Equal(t, newPos.tokensOwed0.ToString(), tc.expectedToken0Owed)
168+
uassert.Equal(t, newPos.tokensOwed1.ToString(), tc.expectedToken1Owed)
169+
}
170+
}
171+
}

pool/position_update.gno

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -39,7 +39,7 @@ func (pool *Pool) updatePosition(positionParams ModifyPositionParams) PositionIn
3939
}
4040
}
4141

42-
feeGrowthInside0X128, feeGrowthInside1X128 := pool.tickGetFeeGrowthInside(
42+
feeGrowthInside0X128, feeGrowthInside1X128 := pool.calculateFeeGrowthInside(
4343
positionParams.tickLower,
4444
positionParams.tickUpper,
4545
pool.slot0.tick,

0 commit comments

Comments
 (0)