Skip to content

Commit

Permalink
Merge pull request #178 from gnoswap-labs/GSW-876-feat-register-token…
Browse files Browse the repository at this point in the history
…-helpers

GSW-876 feat register token helpers
  • Loading branch information
notJoon authored Feb 26, 2024
2 parents d6817a7 + 8c70bab commit afd1752
Show file tree
Hide file tree
Showing 10 changed files with 385 additions and 236 deletions.
41 changes: 41 additions & 0 deletions pool/_TEST_INIT_register_tokens_test.gno
Original file line number Diff line number Diff line change
@@ -1,6 +1,11 @@
package pool

import (
"std"
"testing"

"gno.land/p/demo/testutils"

"gno.land/r/demo/foo"

"gno.land/r/demo/bar"
Expand All @@ -15,6 +20,8 @@ import (

"gno.land/r/demo/gns"

"gno.land/r/demo/consts"

"gno.land/r/demo/users"
)

Expand Down Expand Up @@ -127,6 +134,8 @@ func (GNSToken) Approve() func(spender users.AddressOrName, amount uint64) {
}

func init() {
std.TestSetOrigCaller(consts.GNOSWAP_ADMIN)

RegisterGRC20Interface("gno.land/r/demo/bar", BarToken{})
RegisterGRC20Interface("gno.land/r/demo/foo", FooToken{})
RegisterGRC20Interface("gno.land/r/demo/baz", BazToken{})
Expand All @@ -135,3 +144,35 @@ func init() {
RegisterGRC20Interface("gno.land/r/demo/obl", OBLToken{})
RegisterGRC20Interface("gno.land/r/demo/gns", GNSToken{})
}

func TestGetRegisteredTokens(t *testing.T) {
shouldEQ(t, len(GetRegisteredTokens()), 7)
}

func TestRegisterGRC20Interface(t *testing.T) {
shouldPanic(t,
func() {
RegisterGRC20Interface("gno.land/r/demo/bar", BarToken{})
},
)
}

func TestUnregisterGRC20Interface(t *testing.T) {
dummy := testutils.TestAddress("dummy")
std.TestSetOrigCaller(dummy)

shouldPanic(t,
func() {
UnregisterGRC20Interface("gno.land/r/demo/bar")
},
)

shouldEQ(t, len(GetRegisteredTokens()), 7)

std.TestSetOrigCaller(consts.GNOSWAP_ADMIN)
UnregisterGRC20Interface("gno.land/r/demo/bar")
shouldEQ(t, len(GetRegisteredTokens()), 6)

// re-register to avoid panic in other tests
RegisterGRC20Interface("gno.land/r/demo/bar", BarToken{})
}
94 changes: 30 additions & 64 deletions pool/pool_register.gno
Original file line number Diff line number Diff line change
Expand Up @@ -9,99 +9,68 @@ import (
"gno.land/r/demo/consts"
)

var registered = []GRC20Pair{}

var locked bool // mutex flag

type GRC20Interface interface {
Transfer() func(to users.AddressOrName, amount uint64)
TransferFrom() func(from, to users.AddressOrName, amount uint64)
BalanceOf() func(owner users.AddressOrName) uint64
Approve() func(spender users.AddressOrName, amount uint64)
}

type GRC20Pair struct {
pkgPath string
igrc20 GRC20Interface
}

func findGRC20(pkgPath string) (int, bool) {
pkgPath = handleNative(pkgPath)

for i, pair := range registered {
if pair.pkgPath == pkgPath {
return i, true
}
}

return -1, false
}

func appendGRC20Interface(pkgPath string, igrc20 GRC20Interface) {
pkgPath = handleNative(pkgPath)

registered = append(registered, GRC20Pair{pkgPath: pkgPath, igrc20: igrc20})
}

func removeGRC20Interface(pkgPath string) {
pkgPath = handleNative(pkgPath)
var (
registered = make(map[string]GRC20Interface)
locked = false // mutex
)

i, found := findGRC20(pkgPath)
if !found {
return
func GetRegisteredTokens() []string {
tokens := make([]string, 0, len(registered))
for k := range registered {
tokens = append(tokens, k)
}

registered = append(registered[:i], registered[i+1:]...)
return tokens
}

func RegisterGRC20Interface(pkgPath string, igrc20 GRC20Interface) {
// only admin can register
// r3v4_xxx: below logic can't be used in test case
// r3v4_xxx: however must be used in production

// caller := std.GetOrigCaller()
// if caller != consts.GNOSWAP_ADMIN {
// panic("unauthorized address to register")
// }
caller := std.GetOrigCaller()
if caller != consts.GNOSWAP_ADMIN {
panic(ufmt.Sprintf("[POOL] pool_register.gno__RegisterGRC20Interface() || unauthorized address(%s) to register", caller.String()))
}

pkgPath = handleNative(pkgPath)

_, found := findGRC20(pkgPath)
if !found {
appendGRC20Interface(pkgPath, igrc20)
_, found := registered[pkgPath]
if found {
panic(ufmt.Sprintf("[POOL] pool_register.gno__RegisterGRC20Interface() || pkgPath(%s) already registered", pkgPath))
}

registered[pkgPath] = igrc20
}

func UnregisterGRC20Interface(pkgPath string) {
pkgPath = handleNative(pkgPath)

// do not allow realm to unregister
std.AssertOriginCall()

// only admin can unregister
caller := std.GetOrigCaller()
if caller != consts.GNOSWAP_ADMIN {
panic(ufmt.Sprintf("[POOL] pool_register.gno__UnregisterGRC20Interface() || unauthorized address(%s) to unregister", caller.String()))
}

_, found := findGRC20(pkgPath)
pkgPath = handleNative(pkgPath)

_, found := registered[pkgPath]
if found {
removeGRC20Interface(pkgPath)
delete(registered, pkgPath)
}
}

func transferByRegisterCall(pkgPath string, to std.Address, amount uint64) bool {
pkgPath = handleNative(pkgPath)

i, found := findGRC20(pkgPath)
_, found := registered[pkgPath]
if !found {
panic(ufmt.Sprintf("[POOL] pool_register.gno__transferByRegisterCall() || pkgPath(%s) not found", pkgPath))
// return false
}

if !locked {
locked = true
registered[i].igrc20.Transfer()(users.AddressOrName(to), amount)
registered[pkgPath].Transfer()(users.AddressOrName(to), amount)

defer func() {
locked = false
Expand All @@ -115,15 +84,14 @@ func transferByRegisterCall(pkgPath string, to std.Address, amount uint64) bool
func transferFromByRegisterCall(pkgPath string, from, to std.Address, amount uint64) bool {
pkgPath = handleNative(pkgPath)

i, found := findGRC20(pkgPath)
_, found := registered[pkgPath]
if !found {
panic(ufmt.Sprintf("[POOL] pool_register.gno__transferFromByRegisterCall() || pkgPath(%s) not found", pkgPath))
// return false
}

if !locked {
locked = true
registered[i].igrc20.TransferFrom()(users.AddressOrName(from), users.AddressOrName(to), amount)
registered[pkgPath].TransferFrom()(users.AddressOrName(from), users.AddressOrName(to), amount)

defer func() {
locked = false
Expand All @@ -137,26 +105,24 @@ func transferFromByRegisterCall(pkgPath string, from, to std.Address, amount uin
func balanceOfByRegisterCall(pkgPath string, owner std.Address) uint64 {
pkgPath = handleNative(pkgPath)

i, found := findGRC20(pkgPath)
_, found := registered[pkgPath]
if !found {
panic(ufmt.Sprintf("[POOL] pool_register.gno__balanceOfByRegisterCall() || pkgPath(%s) not found", pkgPath))
// return 0
}

balance := registered[i].igrc20.BalanceOf()(users.AddressOrName(owner))
balance := registered[pkgPath].BalanceOf()(users.AddressOrName(owner))
return balance
}

func approveByRegisterCall(pkgPath string, spender std.Address, amount uint64) bool {
pkgPath = handleNative(pkgPath)

i, found := findGRC20(pkgPath)
_, found := registered[pkgPath]
if !found {
panic(ufmt.Sprintf("[POOL] pool_register.gno__approveByRegisterCall() || pkgPath(%s) not found", pkgPath))
// return false
}

registered[i].igrc20.Approve()(users.AddressOrName(spender), amount)
registered[pkgPath].Approve()(users.AddressOrName(spender), amount)

return true
}
Expand Down
5 changes: 5 additions & 0 deletions position/_TEST_INIT_register_tokens_test.gno
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
package position

import (
"std"

"gno.land/r/demo/foo"

"gno.land/r/demo/bar"
Expand All @@ -15,6 +17,7 @@ import (

"gno.land/r/demo/gns"

"gno.land/r/demo/consts"
"gno.land/r/demo/users"

pl "gno.land/r/demo/pool" // only for position `testcase`` to call grc20 by register
Expand Down Expand Up @@ -129,6 +132,8 @@ func (GNSToken) Approve() func(spender users.AddressOrName, amount uint64) {
}

func init() {
std.TestSetOrigCaller(consts.GNOSWAP_ADMIN)

pl.RegisterGRC20Interface("gno.land/r/demo/bar", BarToken{})
pl.RegisterGRC20Interface("gno.land/r/demo/foo", FooToken{})
pl.RegisterGRC20Interface("gno.land/r/demo/baz", BazToken{})
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ import (
"testing"

"gno.land/p/demo/common"
"gno.land/r/demo/consts"

pl "gno.land/r/demo/pool"

Expand Down Expand Up @@ -95,6 +96,30 @@ func TestCollectFeeBeforeSwap(t *testing.T) {
shouldEQ(t, poolPath, "gno.land/r/demo/bar:gno.land/r/demo/foo:500")
}

func TestSwap(t *testing.T) {
std.TestSetPrevRealm(consts.ROUTER_PATH)
std.TestSetOrigCaller(test1)
amount0, amount1 := pl.Swap(
barPath,
fooPath,
fee500,
test1,
true,
bigint(1_234_567),
consts.MIN_PRICE,
test1,
)
}

func TestCollectFeeAfterSwap(t *testing.T) {
tokenId, fee0, fee1, poolPath := CollectFee(1)
shouldEQ(t, tokenId, uint64(1))
shouldNEQ(t, fee0, bigint(0)) // this is input token
shouldEQ(t, fee1, bigint(0)) // this it output token
shouldEQ(t, poolPath, "gno.land/r/demo/bar:gno.land/r/demo/foo:500")

}

func TestBurnUpperPosition(t *testing.T) {
std.TestSetOrigCaller(test1)

Expand Down
Loading

0 comments on commit afd1752

Please sign in to comment.