Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

GSW-876 feat register token helpers #178

Merged
merged 3 commits into from
Feb 26, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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