Skip to content

Commit af230b5

Browse files
author
0xTopaz
committed
refactor: pool mint
1 parent 765634d commit af230b5

12 files changed

+474
-75
lines changed

_deploy/r/gnoswap/consts/consts.gno

+7-5
Original file line numberDiff line numberDiff line change
@@ -6,9 +6,8 @@ import (
66

77
// GNOSWAP SERVICE
88
const (
9-
ADMIN std.Address = "g17290cwvmrapvp869xfnhhawa8sm9edpufzat7d" // Admin
10-
DEV_OPS std.Address = "g1mjvd83nnjee3z2g7683er55me9f09688pd4mj9" // DevOps
11-
9+
ADMIN std.Address = "g17290cwvmrapvp869xfnhhawa8sm9edpufzat7d"
10+
DEV_OPS std.Address = "g1mjvd83nnjee3z2g7683er55me9f09688pd4mj9"
1211
TOKEN_REGISTER std.Address = "g1er355fkjksqpdtwmhf5penwa82p0rhqxkkyhk5"
1312

1413
TOKEN_REGISTER_NAMESPACE string = "gno.land/r/g1er355fkjksqpdtwmhf5penwa82p0rhqxkkyhk5"
@@ -21,7 +20,8 @@ const (
2120
GNOT string = "gnot"
2221
WRAPPED_WUGNOT string = "gno.land/r/demo/wugnot"
2322

24-
UGNOT_MIN_DEPOSIT_TO_WRAP uint64 = 1000 // defined in https://github.com/gnolang/gno/blob/81a88a2976ba9f2f9127ebbe7fb7d1e1f7fa4bd4/examples/gno.land/r/demo/wugnot/wugnot.gno#L19
23+
// defined in https://github.com/gnolang/gno/blob/81a88a2976ba9f2f9127ebbe7fb7d1e1f7fa4bd4/examples/gno.land/r/demo/wugnot/wugnot.gno#L19
24+
UGNOT_MIN_DEPOSIT_TO_WRAP uint64 = 1000
2525
)
2626

2727
// CONTRACT PATH & ADDRESS
@@ -91,9 +91,11 @@ const (
9191

9292
MAX_UINT128 string = "340282366920938463463374607431768211455"
9393
MAX_UINT160 string = "1461501637330902918203684832716283019655932542975"
94-
MAX_INT256 string = "57896044618658097711785492504343953926634992332820282019728792003956564819968"
9594
MAX_UINT256 string = "115792089237316195423570985008687907853269984665640564039457584007913129639935"
9695

96+
MAX_INT128 string = "170141183460469231731687303715884105727"
97+
MAX_INT256 string = "57896044618658097711785492504343953926634992332820282019728792003956564819968"
98+
9799
// Tick Related
98100
MIN_TICK int32 = -887272
99101
MAX_TICK int32 = 887272

pool/errors.gno

+3-1
Original file line numberDiff line numberDiff line change
@@ -32,7 +32,9 @@ var (
3232
errInvalidTickAndTickSpacing = errors.New("[GNOSWAP-POOL-022] invalid tick and tick spacing requested")
3333
errInvalidAddress = errors.New("[GNOSWAP-POOL-023] invalid address")
3434
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
35+
errUnderflow = errors.New("[GNOSWAP-POOL-025] underflow")
36+
errOverFlow = errors.New("[GNOSWAP-POOL-026] overflow")
37+
errBalanceUpdateFailed = errors.New("[GNOSWAP-POOL-027] balance update failed")
3638
)
3739

3840
// addDetailToError adds detail to an error message

pool/pool.gno

+9-8
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,7 @@ func Mint(
2222
recipient std.Address,
2323
tickLower int32,
2424
tickUpper int32,
25-
_liquidityAmount string,
25+
liquidityAmount string,
2626
positionCaller std.Address,
2727
) (string, string) {
2828
common.IsHalted()
@@ -36,13 +36,14 @@ func Mint(
3636
}
3737
}
3838

39-
liquidityAmount := u256.MustFromDecimal(_liquidityAmount)
40-
if liquidityAmount.IsZero() {
39+
liquidity := u256.MustFromDecimal(liquidityAmount)
40+
if liquidity.IsZero() {
4141
panic(errZeroLiquidity)
4242
}
4343

4444
pool := GetPool(token0Path, token1Path, fee)
45-
position := newModifyPositionParams(recipient, tickLower, tickUpper, i256.FromUint256(liquidityAmount))
45+
liquidityDelta := safeConvertToInt128(liquidity)
46+
position := newModifyPositionParams(recipient, tickLower, tickUpper, liquidityDelta)
4647
_, amount0, amount1 := pool.modifyPosition(position)
4748

4849
if amount0.Gt(u256.Zero()) {
@@ -198,7 +199,7 @@ func SetFeeProtocolByAdmin(
198199

199200
newFee := setFeeProtocol(feeProtocol0, feeProtocol1)
200201

201-
prevAddr, prevRealm := getPrev()
202+
prevAddr, prevRealm := getPrevAsString()
202203
std.Emit(
203204
"SetFeeProtocolByAdmin",
204205
"prevAddr", prevAddr,
@@ -221,7 +222,7 @@ func SetFeeProtocol(feeProtocol0, feeProtocol1 uint8) {
221222

222223
newFee := setFeeProtocol(feeProtocol0, feeProtocol1)
223224

224-
prevAddr, prevRealm := getPrev()
225+
prevAddr, prevRealm := getPrevAsString()
225226
std.Emit(
226227
"SetFeeProtocol",
227228
"prevAddr", prevAddr,
@@ -323,7 +324,7 @@ func CollectProtocolByAdmin(
323324
amount1Requested,
324325
)
325326

326-
prevAddr, prevRealm := getPrev()
327+
prevAddr, prevRealm := getPrevAsString()
327328
std.Emit(
328329
"CollectProtocolByAdmin",
329330
"prevAddr", prevAddr,
@@ -368,7 +369,7 @@ func CollectProtocol(
368369
amount1Requested,
369370
)
370371

371-
prevAddr, prevRealm := getPrev()
372+
prevAddr, prevRealm := getPrevAsString()
372373
std.Emit(
373374
"CollectProtocol",
374375
"prevAddr", prevAddr,

pool/pool_manager.gno

+69-24
Original file line numberDiff line numberDiff line change
@@ -130,12 +130,12 @@ func CreatePool(
130130
token0Path string,
131131
token1Path string,
132132
fee uint32,
133-
_sqrtPriceX96 string,
133+
sqrtPriceX96 string,
134134
) {
135135
common.IsHalted()
136136
en.MintAndDistributeGns()
137137

138-
poolInfo := newPoolParams(token0Path, token1Path, fee, _sqrtPriceX96)
138+
poolInfo := newPoolParams(token0Path, token1Path, fee, sqrtPriceX96)
139139

140140
if poolInfo.isSameTokenPath() {
141141
panic(addDetailToError(
@@ -153,7 +153,7 @@ func CreatePool(
153153
poolPath := GetPoolPath(token0Path, token1Path, fee)
154154

155155
// reinitialize poolInfo with wrapped tokens
156-
poolInfo = newPoolParams(token0Path, token1Path, fee, _sqrtPriceX96)
156+
poolInfo = newPoolParams(token0Path, token1Path, fee, sqrtPriceX96)
157157

158158
// then check if token0Path == token1Path
159159
if poolInfo.isSameTokenPath() {
@@ -174,7 +174,7 @@ func CreatePool(
174174
}
175175

176176
// TODO: make this as a parameter
177-
prevAddr, prevRealm := getPrev()
177+
prevAddr, prevRealm := getPrevAsString()
178178

179179
// check whether the pool already exist
180180
pool, exist := pools.Get(poolPath)
@@ -208,7 +208,7 @@ func CreatePool(
208208
"token0Path", token0Path,
209209
"token1Path", token1Path,
210210
"fee", ufmt.Sprintf("%d", fee),
211-
"sqrtPriceX96", _sqrtPriceX96,
211+
"sqrtPriceX96", sqrtPriceX96,
212212
"internal_poolPath", poolPath,
213213
)
214214
}
@@ -220,46 +220,91 @@ func DoesPoolPathExist(poolPath string) bool {
220220
return exist
221221
}
222222

223-
// GetPool retrieves the pool for the given token paths and fee.
224-
// It constructs the poolPath from the given parameters and returns the corresponding pool.
225-
// Returns pool struct
223+
// GetPool retrieves a pool instance based on the provided token paths and fee tier.
224+
//
225+
// This function determines the pool path by combining the paths of token0 and token1 along with the fee tier,
226+
// and then retrieves the corresponding pool instance using that path.
227+
//
228+
// Parameters:
229+
// - token0Path (string): The unique identifier or path for token0.
230+
// - token1Path (string): The unique identifier or path for token1.
231+
// - fee (uint32): The fee tier for the pool, expressed in basis points (e.g., 3000 for 0.3%).
232+
//
233+
// Returns:
234+
// - *Pool: A pointer to the Pool instance corresponding to the provided tokens and fee tier.
235+
//
236+
// Notes:
237+
// - The order of token paths (token0Path and token1Path) matters and should match the pool's configuration.
238+
// - Ensure that the tokens and fee tier provided are valid and registered in the system.
239+
//
240+
// Example:
241+
// pool := GetPool("path/to/token0", "path/to/token1", 3000)
226242
func GetPool(token0Path, token1Path string, fee uint32) *Pool {
227243
poolPath := GetPoolPath(token0Path, token1Path, fee)
228-
pool, exist := pools[poolPath]
229-
if !exist {
230-
panic(addDetailToError(
231-
errDataNotFound,
232-
ufmt.Sprintf("pool_manager.gno__GetPool() || expected poolPath(%s) to exist", poolPath),
233-
))
234-
}
235-
236-
return pool
244+
return GetPoolFromPoolPath(poolPath)
237245
}
238246

239-
// GetPoolFromPoolPath retrieves the pool for the given poolPath.
247+
// GetPoolFromPoolPath retrieves a pool instance based on the provided pool path.
248+
//
249+
// This function checks if a pool exists for the given poolPath in the `pools` mapping.
250+
// If the pool exists, it returns the pool instance. Otherwise, it panics with a descriptive error.
251+
//
252+
// Parameters:
253+
// - poolPath (string): The unique identifier or path for the pool.
254+
//
255+
// Returns:
256+
// - *Pool: A pointer to the Pool instance corresponding to the given poolPath.
257+
//
258+
// Panics:
259+
// - If the `poolPath` does not exist in the `pools` mapping, it panics with an error message
260+
// indicating that the expected poolPath was not found.
261+
//
262+
// Notes:
263+
// - Ensure that the `poolPath` provided is valid and corresponds to an existing pool in the `pools` mapping.
264+
//
265+
// Example:
266+
// pool := GetPoolFromPoolPath("path/to/pool")
240267
func GetPoolFromPoolPath(poolPath string) *Pool {
241268
pool, exist := pools[poolPath]
242269
if !exist {
243270
panic(addDetailToError(
244271
errDataNotFound,
245-
ufmt.Sprintf("pool_manager.gno__GetPoolFromPoolPath() || expected poolPath(%s) to exist", poolPath),
272+
ufmt.Sprintf("expected poolPath(%s) to exist", poolPath),
246273
))
247274
}
248-
249275
return pool
250276
}
251277

252-
// GetPoolPath generates a poolPath from the given token paths and fee.
253-
// The poolPath is constructed by joining the token paths and fee with colons.
278+
// GetPoolPath generates a unique pool path string based on the token paths and fee tier.
279+
//
280+
// This function ensures that the token paths are registered and sorted in alphabetical order
281+
// before combining them with the fee tier to create a unique identifier for the pool.
282+
//
283+
// Parameters:
284+
// - token0Path (string): The unique identifier or path for token0.
285+
// - token1Path (string): The unique identifier or path for token1.
286+
// - fee (uint32): The fee tier for the pool, expressed in basis points (e.g., 3000 for 0.3%).
287+
//
288+
// Returns:
289+
// - string: A unique pool path string in the format "token0Path:token1Path:fee".
290+
//
291+
// Notes:
292+
// - The function validates that both `token0Path` and `token1Path` are registered in the system
293+
// using `common.MustRegistered`.
294+
// - The token paths are sorted alphabetically to ensure consistent pool path generation, regardless
295+
// of the input order.
296+
// - This sorting guarantees that the pool path remains deterministic for the same pair of tokens and fee.
297+
//
298+
// Example:
299+
// poolPath := GetPoolPath("path/to/token0", "path/to/token1", 3000)
300+
// // Output: "path/to/token0:path/to/token1:3000"
254301
func GetPoolPath(token0Path, token1Path string, fee uint32) string {
255302
common.MustRegistered(token0Path)
256303
common.MustRegistered(token1Path)
257304

258-
// TODO: this check is not unnecessary, if we are sure that
259305
// all the token paths in the pool are sorted in alphabetical order.
260306
if strings.Compare(token1Path, token0Path) < 0 {
261307
token0Path, token1Path = token1Path, token0Path
262308
}
263-
264309
return ufmt.Sprintf("%s:%s:%d", token0Path, token1Path, fee)
265310
}

pool/pool_manager_test.gno

+56
Original file line numberDiff line numberDiff line change
@@ -202,3 +202,59 @@ func TestCreatePool(t *testing.T) {
202202

203203
resetObject(t)
204204
}
205+
206+
func TestGetPool(t *testing.T) {
207+
tests := []struct {
208+
name string
209+
setupFn func(t *testing.T)
210+
action func(t *testing.T)
211+
shouldPanic bool
212+
expected string
213+
}{
214+
{
215+
name: "Panic - unregisterd poolPath ",
216+
setupFn: func(t *testing.T) {
217+
InitialisePoolTest(t)
218+
},
219+
action: func(t *testing.T) {
220+
GetPool(barPath, fooPath, fee500)
221+
},
222+
shouldPanic: true,
223+
expected: "[GNOSWAP-POOL-008] requested data not found || expected poolPath(gno.land/r/onbloc/bar:gno.land/r/onbloc/foo:500) to exist",
224+
},
225+
}
226+
227+
for _, tt := range tests {
228+
t.Run(tt.name, func(t *testing.T) {
229+
defer func() {
230+
if r := recover(); r == nil {
231+
if tt.shouldPanic {
232+
t.Errorf(">>> %s: expected panic but got none", tt.name)
233+
return
234+
}
235+
} else {
236+
switch r.(type) {
237+
case string:
238+
if r.(string) != tt.expected {
239+
t.Errorf(">>> %s: got panic %v, want %v", tt.name, r, tt.expected)
240+
}
241+
case error:
242+
if r.(error).Error() != tt.expected {
243+
t.Errorf(">>> %s: got panic %v, want %v", tt.name, r.(error).Error(), tt.expected)
244+
}
245+
default:
246+
t.Errorf(">>> %s: got panic %v, want %v", tt.name, r, tt.expected)
247+
}
248+
}
249+
}()
250+
if tt.setupFn != nil {
251+
tt.setupFn(t)
252+
}
253+
254+
if tt.shouldPanic {
255+
tt.action(t)
256+
} else {
257+
}
258+
})
259+
}
260+
}

pool/pool_transfer.gno

+31-13
Original file line numberDiff line numberDiff line change
@@ -53,10 +53,7 @@ func (p *Pool) transferAndVerify(
5353
if err := validatePoolBalance(token0, token1, absAmount, isToken0); err != nil {
5454
panic(err)
5555
}
56-
amountUint64, err := safeConvertToUint64(absAmount)
57-
if err != nil {
58-
panic(err)
59-
}
56+
amountUint64 := safeConvertToUint64(absAmount)
6057

6158
token := common.GetTokenTeller(tokenPath)
6259
checkTransferError(token.Transfer(to, amountUint64))
@@ -98,20 +95,41 @@ func (p *Pool) transferFromAndVerify(
9895
amount *u256.Uint,
9996
isToken0 bool,
10097
) {
101-
absAmount := amount
102-
amountUint64, err := safeConvertToUint64(absAmount)
103-
if err != nil {
104-
panic(err)
105-
}
98+
amountUint64 := safeConvertToUint64(amount)
10699

107-
token := common.GetTokenTeller(tokenPath)
108-
checkTransferError(token.TransferFrom(from, to, amountUint64))
100+
token := common.GetToken(tokenPath)
101+
beforeBalance := token.BalanceOf(to)
102+
103+
teller := common.GetTokenTeller(tokenPath)
104+
checkTransferError(teller.TransferFrom(from, to, amountUint64))
105+
106+
afterBalance := token.BalanceOf(to)
107+
if (beforeBalance + amountUint64) != afterBalance {
108+
panic(ufmt.Sprintf(
109+
"%v. beforeBalance(%d) + amount(%d) != afterBalance(%d)",
110+
errTransferFailed, beforeBalance, amountUint64, afterBalance,
111+
))
112+
}
109113

110114
// update pool balances
111115
if isToken0 {
112-
p.balances.token0 = new(u256.Uint).Add(p.balances.token0, absAmount)
116+
beforeToken0 := p.balances.token0.Clone()
117+
p.balances.token0 = new(u256.Uint).Add(p.balances.token0, amount)
118+
if p.balances.token0.Lt(beforeToken0) {
119+
panic(ufmt.Sprintf(
120+
"%v. token0(%s) < beforeToken0(%s)",
121+
errBalanceUpdateFailed, p.balances.token0.ToString(), beforeToken0.ToString(),
122+
))
123+
}
113124
} else {
114-
p.balances.token1 = new(u256.Uint).Add(p.balances.token1, absAmount)
125+
beforeToken1 := p.balances.token1.Clone()
126+
p.balances.token1 = new(u256.Uint).Add(p.balances.token1, amount)
127+
if p.balances.token1.Lt(beforeToken1) {
128+
panic(ufmt.Sprintf(
129+
"%v. token1(%s) < beforeToken1(%s)",
130+
errBalanceUpdateFailed, p.balances.token1.ToString(), beforeToken1.ToString(),
131+
))
132+
}
115133
}
116134
}
117135

pool/pool_transfer_test.gno

+2-2
Original file line numberDiff line numberDiff line change
@@ -134,8 +134,8 @@ func TestTransferFromAndVerify(t *testing.T) {
134134

135135
for _, tt := range tests {
136136
t.Run(tt.name, func(t *testing.T) {
137-
TokenFaucet(t, fooPath, pusers.AddressOrName(tt.from))
138-
TokenApprove(t, fooPath, pusers.AddressOrName(tt.from), pool, u256.MustFromDecimal(tt.amount.ToString()).Uint64())
137+
TokenFaucet(t, tt.tokenPath, pusers.AddressOrName(tt.from))
138+
TokenApprove(t, tt.tokenPath, pusers.AddressOrName(tt.from), pool, u256.MustFromDecimal(tt.amount.ToString()).Uint64())
139139

140140
tt.pool.transferFromAndVerify(tt.from, tt.to, tt.tokenPath, u256.MustFromDecimal(tt.amount.ToString()), tt.isToken0)
141141

0 commit comments

Comments
 (0)