Skip to content

Commit 78dfa75

Browse files
notJoononlyhyde0xTopaz
authored
Merge pull request #414 from gnoswap-labs/refactor/pool_grc20reg
* GSW-1838 refactor: use grc20reg - use gno's grc20reg realm to support dynamic token transfer in pool * GSW-1838 feat: grc20reg - replace previous token_register to latest grc20reg * feat: update grc20 spec for grc20reg * hotfix: update bar token spec * feat: get token object from `grc20-reg` in `common` * fix: typo * chore: remove grc20reg - it's been merged into master of gnolang/gno * feat: get `token` and `teller` object from grc20reg * test: txtar for approve & transferfrom using grc20reg * feat: use teller to transfer token * feat: IsRegistered() to check if token is registered or not * refactor: remove old token_register * chore: rename teller * feat: guard logic to see if token is registered * feat: MustRegistered in common - if token is not registered, it will panic. * chore: rename * GSW-1838 fix: test errors are fixed (#422) * GSW-1838 fix: test errors are fixed - Integrate helper functions for tests - Change file extensions to prevent test code in the test folder from being executed - Fixing failure errors due to code integration - Known issue : Fixed additional test failure case related to getter * fix: remove time compare in unit test * fix: do not setup data in init * test: pool manger testcase --------- Co-authored-by: n3wbie <[email protected]> * GSW-1838 refactor: use grc20reg - use gno's grc20reg realm to support dynamic token transfer in pool * fix: gno.mod tidy * fix: missing guard logic for HandleWithdrawalFee * fix: failing testcase * fix: tc * feat: use teller to transfer/transferfrom * test: fix mocking old functions * test: remove hardcoded value * test: detail error message * fix: typo * remove: duplicate token register check * fix: typo * refactor: duplicate token register check - GetPoolPath has check function --------- Co-authored-by: 0xTopaz <[email protected]> Co-authored-by: 0xTopaz <[email protected]>
2 parents c86dab4 + 2e656ad commit 78dfa75

15 files changed

+161
-539
lines changed

_deploy/r/gnoswap/common/errors.gno

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -7,9 +7,10 @@ import (
77
)
88

99
var (
10-
errNoPermission = errors.New("[GNOSWAP-COMMON-001] caller has no permission")
11-
errHalted = errors.New("[GNOSWAP-COMMON-002] halted")
12-
errOutOfRange = errors.New("[GNOSWAP-COMMON-003] value out of range")
10+
errNoPermission = errors.New("[GNOSWAP-COMMON-001] caller has no permission")
11+
errHalted = errors.New("[GNOSWAP-COMMON-002] halted")
12+
errOutOfRange = errors.New("[GNOSWAP-COMMON-003] value out of range")
13+
errNotRegistered = errors.New("[GNOSWAP-COMMON-004] token is not registered")
1314
)
1415

1516
func addDetailToError(err error, detail string) string {

_deploy/r/gnoswap/common/grc20reg_helper.gno

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -44,3 +44,14 @@ func IsRegistered(path string) error {
4444
}
4545
return nil
4646
}
47+
48+
// MustRegistered is a helper function to check if token is registered to grc20reg
49+
// if token is not registered, it will panic
50+
func MustRegistered(path string) {
51+
if err := IsRegistered(path); err != nil {
52+
panic(addDetailToError(
53+
errNotRegistered,
54+
ufmt.Sprintf("token(%s) is not registered", path),
55+
))
56+
}
57+
}

_deploy/r/gnoswap/common/grc20reg_helper_test.gno

Lines changed: 30 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -16,20 +16,20 @@ var (
1616
)
1717

1818
func TestGetToken(t *testing.T) {
19-
t.Run("registered(by default)", func(t *testing.T) {
19+
t.Run("get regsitered token", func(t *testing.T) {
2020
token := GetToken(tokenPath)
2121
if token == nil {
22-
t.Error("Expected non-nil teller for foo20")
22+
t.Error("Expected non-nil token for foo20")
2323
}
2424
})
2525

26-
t.Run("not registered", func(t *testing.T) {
26+
t.Run("get non registered token", func(t *testing.T) {
2727
defer func() {
2828
if r := recover(); r == nil {
2929
t.Errorf("Expected panic for non-registered token")
3030
}
3131
}()
32-
GetToken("not_registered")
32+
GetToken("not_registered_token")
3333
})
3434
}
3535

@@ -75,20 +75,20 @@ func TestTokenMethod(t *testing.T) {
7575
}
7676

7777
func TestGetTokenTeller(t *testing.T) {
78-
t.Run("registered(by default)", func(t *testing.T) {
78+
t.Run("get registered token teller", func(t *testing.T) {
7979
teller := GetTokenTeller(tokenPath)
8080
if teller == nil {
8181
t.Error("Expected non-nil teller for foo20")
8282
}
8383
})
8484

85-
t.Run("not registered", func(t *testing.T) {
85+
t.Run("get non registered token teller", func(t *testing.T) {
8686
defer func() {
8787
if r := recover(); r == nil {
88-
t.Errorf("Expected panic for non-registered token")
88+
t.Errorf("Expected panic for non-registered token teller")
8989
}
9090
}()
91-
GetTokenTeller("not_registered")
91+
GetTokenTeller("not_registered_teller")
9292
})
9393
}
9494

@@ -129,6 +129,26 @@ func TestTellerMethod(t *testing.T) {
129129
}
130130

131131
func TestIsRegistered(t *testing.T) {
132-
uassert.NoError(t, IsRegistered(tokenPath))
133-
uassert.Error(t, IsRegistered("not_registered"))
132+
t.Run("check if token is registered", func(t *testing.T) {
133+
uassert.NoError(t, IsRegistered(tokenPath))
134+
})
135+
136+
t.Run("check if token is not registered", func(t *testing.T) {
137+
uassert.Error(t, IsRegistered("not_registered_token"))
138+
})
139+
}
140+
141+
func TestMustRegistered(t *testing.T) {
142+
t.Run("must be registered", func(t *testing.T) {
143+
MustRegistered(tokenPath)
144+
})
145+
146+
t.Run("panic for non registered token", func(t *testing.T) {
147+
defer func() {
148+
if r := recover(); r == nil {
149+
t.Errorf("Expected panic for non-registered token")
150+
}
151+
}()
152+
MustRegistered("not_registered")
153+
})
134154
}

pool/_helper_test.gno

Lines changed: 0 additions & 117 deletions
Original file line numberDiff line numberDiff line change
@@ -45,123 +45,6 @@ const (
4545
addr02 = testutils.TestAddress("addr02")
4646
)
4747

48-
type WugnotToken struct{}
49-
50-
func (WugnotToken) Transfer() func(to pusers.AddressOrName, amount uint64) {
51-
return wugnot.Transfer
52-
}
53-
func (WugnotToken) TransferFrom() func(from, to pusers.AddressOrName, amount uint64) {
54-
return wugnot.TransferFrom
55-
}
56-
func (WugnotToken) BalanceOf() func(owner pusers.AddressOrName) uint64 {
57-
return wugnot.BalanceOf
58-
}
59-
func (WugnotToken) Approve() func(spender pusers.AddressOrName, amount uint64) {
60-
return wugnot.Approve
61-
}
62-
63-
type GNSToken struct{}
64-
65-
func (GNSToken) Transfer() func(to pusers.AddressOrName, amount uint64) {
66-
return gns.Transfer
67-
}
68-
func (GNSToken) TransferFrom() func(from, to pusers.AddressOrName, amount uint64) {
69-
return gns.TransferFrom
70-
}
71-
func (GNSToken) BalanceOf() func(owner pusers.AddressOrName) uint64 {
72-
return gns.BalanceOf
73-
}
74-
func (GNSToken) Approve() func(spender pusers.AddressOrName, amount uint64) {
75-
return gns.Approve
76-
}
77-
78-
type BarToken struct{}
79-
80-
func (BarToken) Transfer() func(to pusers.AddressOrName, amount uint64) {
81-
return bar.Transfer
82-
}
83-
func (BarToken) TransferFrom() func(from, to pusers.AddressOrName, amount uint64) {
84-
return bar.TransferFrom
85-
}
86-
func (BarToken) BalanceOf() func(owner pusers.AddressOrName) uint64 {
87-
return bar.BalanceOf
88-
}
89-
func (BarToken) Approve() func(spender pusers.AddressOrName, amount uint64) {
90-
return bar.Approve
91-
}
92-
93-
type BazToken struct{}
94-
95-
func (BazToken) Transfer() func(to pusers.AddressOrName, amount uint64) {
96-
return baz.Transfer
97-
}
98-
func (BazToken) TransferFrom() func(from, to pusers.AddressOrName, amount uint64) {
99-
return baz.TransferFrom
100-
}
101-
func (BazToken) BalanceOf() func(owner pusers.AddressOrName) uint64 {
102-
return baz.BalanceOf
103-
}
104-
func (BazToken) Approve() func(spender pusers.AddressOrName, amount uint64) {
105-
return baz.Approve
106-
}
107-
108-
type FooToken struct{}
109-
110-
func (FooToken) Transfer() func(to pusers.AddressOrName, amount uint64) {
111-
return foo.Transfer
112-
}
113-
func (FooToken) TransferFrom() func(from, to pusers.AddressOrName, amount uint64) {
114-
return foo.TransferFrom
115-
}
116-
func (FooToken) BalanceOf() func(owner pusers.AddressOrName) uint64 {
117-
return foo.BalanceOf
118-
}
119-
func (FooToken) Approve() func(spender pusers.AddressOrName, amount uint64) {
120-
return foo.Approve
121-
}
122-
123-
type OBLToken struct{}
124-
125-
func (OBLToken) Transfer() func(to pusers.AddressOrName, amount uint64) {
126-
return obl.Transfer
127-
}
128-
func (OBLToken) TransferFrom() func(from, to pusers.AddressOrName, amount uint64) {
129-
return obl.TransferFrom
130-
}
131-
func (OBLToken) BalanceOf() func(owner pusers.AddressOrName) uint64 {
132-
return obl.BalanceOf
133-
}
134-
func (OBLToken) Approve() func(spender pusers.AddressOrName, amount uint64) {
135-
return obl.Approve
136-
}
137-
138-
type QuxToken struct{}
139-
140-
func (QuxToken) Transfer() func(to pusers.AddressOrName, amount uint64) {
141-
return qux.Transfer
142-
}
143-
func (QuxToken) TransferFrom() func(from, to pusers.AddressOrName, amount uint64) {
144-
return qux.TransferFrom
145-
}
146-
func (QuxToken) BalanceOf() func(owner pusers.AddressOrName) uint64 {
147-
return qux.BalanceOf
148-
}
149-
func (QuxToken) Approve() func(spender pusers.AddressOrName, amount uint64) {
150-
return qux.Approve
151-
}
152-
153-
func init() {
154-
std.TestSetRealm(std.NewUserRealm(consts.TOKEN_REGISTER))
155-
156-
RegisterGRC20Interface(wugnotPath, WugnotToken{})
157-
RegisterGRC20Interface(gnsPath, GNSToken{})
158-
RegisterGRC20Interface(barPath, BarToken{})
159-
RegisterGRC20Interface(bazPath, BazToken{})
160-
RegisterGRC20Interface(fooPath, FooToken{})
161-
RegisterGRC20Interface(oblPath, OBLToken{})
162-
RegisterGRC20Interface(quxPath, QuxToken{})
163-
}
164-
16548
var (
16649
admin = pusers.AddressOrName(consts.ADMIN)
16750
alice = pusers.AddressOrName(testutils.TestAddress("alice"))

pool/pool.gno

Lines changed: 44 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -145,12 +145,18 @@ func Collect(
145145
// Smallest of three: amount0Requested, position.tokensOwed0, pool.balances.token0
146146
amount0Req := u256.MustFromDecimal(amount0Requested)
147147
amount0, position.tokensOwed0, pool.balances.token0 = collectToken(amount0Req, position.tokensOwed0, pool.balances.token0)
148-
transferByRegisterCall(pool.token0Path, recipient, amount0.Uint64())
148+
token0 := common.GetTokenTeller(pool.token0Path)
149+
checkTransferError(token0.Transfer(recipient, amount0.Uint64()))
149150

150151
// Smallest of three: amount0Requested, position.tokensOwed0, pool.balances.token0
151152
amount1Req := u256.MustFromDecimal(amount1Requested)
152153
amount1, position.tokensOwed1, pool.balances.token1 = collectToken(amount1Req, position.tokensOwed1, pool.balances.token1)
153-
transferByRegisterCall(pool.token1Path, recipient, amount1.Uint64())
154+
155+
// Update state first then transfer
156+
position.tokensOwed1 = new(u256.Uint).Sub(position.tokensOwed1, amount1)
157+
pool.balances.token1 = new(u256.Uint).Sub(pool.balances.token1, amount1)
158+
token1 := common.GetTokenTeller(pool.token1Path)
159+
checkTransferError(token1.Transfer(recipient, amount1.Uint64()))
154160

155161
pool.positions[positionKey] = position
156162

@@ -175,15 +181,15 @@ func collectToken(
175181
// SwapResult encapsulates all state changes that occur as a result of a swap
176182
// This type ensure all state transitions are atomic and can be applied at once.
177183
type SwapResult struct {
178-
Amount0 *i256.Int
179-
Amount1 *i256.Int
180-
NewSqrtPrice *u256.Uint
181-
NewTick int32
182-
NewLiquidity *u256.Uint
183-
NewProtocolFees ProtocolFees
184+
Amount0 *i256.Int
185+
Amount1 *i256.Int
186+
NewSqrtPrice *u256.Uint
187+
NewTick int32
188+
NewLiquidity *u256.Uint
189+
NewProtocolFees ProtocolFees
184190
FeeGrowthGlobal0X128 *u256.Uint
185191
FeeGrowthGlobal1X128 *u256.Uint
186-
SwapFee *u256.Uint
192+
SwapFee *u256.Uint
187193
}
188194

189195
// SwapComputation encapsulates pure computation logic for swap
@@ -294,10 +300,11 @@ func Swap(
294300
// The function follows these state transitions:
295301
// 1. Initial State: Provided by `SwapComputation.InitialState`
296302
// 2. Stepping State: For each step:
297-
// - Compute next tick and price target
298-
// - Calculate amounts and fees
299-
// - Update state (remaining amount, fees, liquidity)
300-
// - Handle tick transitions if necessary
303+
// - Compute next tick and price target
304+
// - Calculate amounts and fees
305+
// - Update state (remaining amount, fees, liquidity)
306+
// - Handle tick transitions if necessary
307+
//
301308
// 3. Final State: Aggregated in SwapResult
302309
//
303310
// The computation continues until either:
@@ -309,7 +316,6 @@ func computeSwap(pool *Pool, comp SwapComputation) (*SwapResult, error) {
309316
state := comp.InitialState
310317
swapFee := u256.Zero()
311318

312-
313319
var newFee *u256.Uint
314320
var err error
315321

@@ -342,7 +348,7 @@ func computeSwap(pool *Pool, comp SwapComputation) (*SwapResult, error) {
342348
},
343349
FeeGrowthGlobal0X128: pool.feeGrowthGlobal0X128,
344350
FeeGrowthGlobal1X128: pool.feeGrowthGlobal1X128,
345-
SwapFee: swapFee,
351+
SwapFee: swapFee,
346352
}
347353

348354
// Update protocol fees if necessary
@@ -377,6 +383,7 @@ func applySwapResult(pool *Pool, result *SwapResult) {
377383
// For zeroForOne (selling token0):
378384
// - Price limit must be below current price
379385
// - Price limit must be above MIN_SQRT_RATIO
386+
//
380387
// For !zeroForOne (selling token1):
381388
// - Price limit must be above current price
382389
// - Price limit must be below MAX_SQRT_RATIO
@@ -562,6 +569,7 @@ func computeAmounts(state SwapState, sqrtRatioTargetX96 *u256.Uint, pool *Pool,
562569
// For exact input swaps:
563570
// - Decrements remaining input amount by (amountIn + feeAmount)
564571
// - Decrements calculated amount by amountOut
572+
//
565573
// For exact output swaps:
566574
// - Increments remaining output amount by amountOut
567575
// - Increments calculated amount by (amountIn + feeAmount)
@@ -717,9 +725,12 @@ func CollectProtocolByAdmin(
717725
token1Path string,
718726
fee uint32,
719727
recipient std.Address,
720-
amount0Requested string,
721-
amount1Requested string,
722-
) (string, string) {
728+
amount0Requested string, // uint128
729+
amount1Requested string, // uint128
730+
) (string, string) { // uint128 x2
731+
common.MustRegistered(token0Path)
732+
common.MustRegistered(token1Path)
733+
723734
caller := std.PrevRealm().Addr()
724735
if err := common.AdminOnly(caller); err != nil {
725736
panic(err)
@@ -759,9 +770,12 @@ func CollectProtocol(
759770
token1Path string,
760771
fee uint32,
761772
recipient std.Address,
762-
amount0Requested string,
763-
amount1Requested string,
764-
) (string, string) {
773+
amount0Requested string, // uint128
774+
amount1Requested string, // uint128
775+
) (string, string) { // uint128 x2
776+
common.MustRegistered(token0Path)
777+
common.MustRegistered(token1Path)
778+
765779
caller := std.PrevRealm().Addr()
766780
if err := common.GovernanceOnly(caller); err != nil {
767781
panic(err)
@@ -814,8 +828,11 @@ func collectProtocol(
814828
uAmount0 := amount0.Uint64()
815829
uAmount1 := amount1.Uint64()
816830

817-
transferByRegisterCall(pool.token0Path, recipient, uAmount0)
818-
transferByRegisterCall(pool.token1Path, recipient, uAmount1)
831+
token0Teller := common.GetTokenTeller(pool.token0Path)
832+
checkTransferError(token0Teller.Transfer(recipient, uAmount0))
833+
834+
token1Teller := common.GetTokenTeller(pool.token1Path)
835+
checkTransferError(token1Teller.Transfer(recipient, uAmount1))
819836

820837
return amount0.ToString(), amount1.ToString()
821838
}
@@ -866,7 +883,8 @@ func (pool *Pool) transferAndVerify(
866883
panic(err)
867884
}
868885

869-
transferByRegisterCall(tokenPath, to, amountUint64)
886+
token := common.GetTokenTeller(tokenPath)
887+
checkTransferError(token.Transfer(to, amountUint64))
870888

871889
newBalance, err := updatePoolBalance(token0, token1, absAmount, isToken0)
872890
if err != nil {
@@ -943,12 +961,8 @@ func (pool *Pool) transferFromAndVerify(
943961
panic(err)
944962
}
945963

946-
// try sending
947-
// will panic if following conditions are met:
948-
// - POOL does not have enough approved amount
949-
// - from does not have enough balance
950-
// - token is not registered
951-
transferFromByRegisterCall(tokenPath, from, to, amountUint64)
964+
token := common.GetTokenTeller(tokenPath)
965+
checkTransferError(token.TransferFrom(from, to, amountUint64))
952966

953967
// update pool balances
954968
if isToken0 {

0 commit comments

Comments
 (0)