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-1838 feat: grc20reg #412

Merged
merged 6 commits into from
Dec 10, 2024
Merged
Show file tree
Hide file tree
Changes from 3 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
53 changes: 53 additions & 0 deletions __local/grc20_tokens/grc20reg/approve_and_transferfrom.txtar
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
loadpkg gno.land/p/demo/users

loadpkg gno.land/r/demo/foo20
loadpkg gno.land/r/demo/grc20reg

loadpkg gno.land/r/demo/echo $WORK/echo

## start a new node
gnoland start

## faucet
# gnokey maketx call -pkgpath gno.land/r/demo/foo20 -func Faucet -gas-fee 1ugnot -gas-wanted 4000000 -broadcast -chainid=tendermint_test test1

## print reg addr
gnokey maketx call -pkgpath gno.land/r/demo/reg -func RelamAddr -gas-fee 1ugnot -gas-wanted 4000000 -broadcast -chainid=tendermint_test test1
stdout 'g19tlskvga928es8ug2empargp0teul03apzjud9'

## approve
gnokey maketx call -pkgpath gno.land/r/demo/foo20 -func Approve -args 'g19tlskvga928es8ug2empargp0teul03apzjud9' -args '100' -gas-fee 1ugnot -gas-wanted 4000000 -broadcast -chainid=tendermint_test test1

## transfer from
gnokey maketx call -pkgpath gno.land/r/demo/reg -func TransferFromWithReg -gas-fee 1ugnot -gas-wanted 4000000 -broadcast -chainid=tendermint_test test1
stdout ''

-- reg/reg.gno --
package reg

import (
"std"

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

func RelamAddr() string {
addr := std.CurrentRealm().Addr().String()
return addr
}

func TransferFromWithReg() {
caller := std.PrevRealm().Addr()
curr := std.CurrentRealm().Addr()


// using import
// foo20.TransferFrom(uCaller, uCurr, uint64(100))

// using grc20reg
fooTokenGetter := grc20reg.Get("gno.land/r/demo/foo20")
fooToken := fooTokenGetter()
userTeller := fooToken.CallerTeller()

userTeller.TransferFrom(caller, curr, uint64(100))
}
9 changes: 9 additions & 0 deletions __local/grc20_tokens/grc20reg/gno.mod
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
module gno.land/r/gnoswap/v1/grc20reg

require (
gno.land/p/demo/avl v0.0.0-latest
gno.land/p/demo/fqname v0.0.0-latest
gno.land/p/demo/grc/grc20 v0.0.0-latest
gno.land/p/demo/ufmt v0.0.0-latest
gno.land/p/demo/urequire v0.0.0-latest
)
76 changes: 76 additions & 0 deletions __local/grc20_tokens/grc20reg/grc20reg.gno
Original file line number Diff line number Diff line change
@@ -0,0 +1,76 @@
package grc20reg

import (
"std"

"gno.land/p/demo/avl"
"gno.land/p/demo/fqname"
"gno.land/p/demo/grc/grc20"
"gno.land/p/demo/ufmt"
)

var registry = avl.NewTree() // rlmPath[.slug] -> TokenGetter (slug is optional)

func Register(tokenGetter grc20.TokenGetter, slug string) {
rlmPath := std.PrevRealm().PkgPath()
key := fqname.Construct(rlmPath, slug)
registry.Set(key, tokenGetter)
std.Emit(
registerEvent,
"pkgpath", rlmPath,
"slug", slug,
)
}

func Get(key string) grc20.TokenGetter {
tokenGetter, ok := registry.Get(key)
if !ok {
return nil
}
return tokenGetter.(grc20.TokenGetter)
}

func MustGet(key string) grc20.TokenGetter {
tokenGetter := Get(key)
if tokenGetter == nil {
panic("unknown token: " + key)
}
return tokenGetter
}

func Render(path string) string {
switch {
case path == "": // home
// TODO: add pagination
s := ""
count := 0
registry.Iterate("", "", func(key string, tokenI interface{}) bool {
count++
tokenGetter := tokenI.(grc20.TokenGetter)
token := tokenGetter()
rlmPath, slug := fqname.Parse(key)
rlmLink := fqname.RenderLink(rlmPath, slug)
infoLink := "/r/demo/grc20reg:" + key
s += ufmt.Sprintf("- **%s** - %s - [info](%s)\n", token.GetName(), rlmLink, infoLink)
return false
})
if count == 0 {
return "No registered token."
}
return s
default: // specific token
key := path
tokenGetter := MustGet(key)
token := tokenGetter()
rlmPath, slug := fqname.Parse(key)
rlmLink := fqname.RenderLink(rlmPath, slug)
s := ufmt.Sprintf("# %s\n", token.GetName())
s += ufmt.Sprintf("- symbol: **%s**\n", token.GetSymbol())
s += ufmt.Sprintf("- realm: %s\n", rlmLink)
s += ufmt.Sprintf("- decimals: %d\n", token.GetDecimals())
s += ufmt.Sprintf("- total supply: %d\n", token.TotalSupply())
return s
}
}

const registerEvent = "register"
59 changes: 59 additions & 0 deletions __local/grc20_tokens/grc20reg/grc20reg_test.gno
Original file line number Diff line number Diff line change
@@ -0,0 +1,59 @@
package grc20reg

import (
"std"
"strings"
"testing"

"gno.land/p/demo/grc/grc20"
"gno.land/p/demo/urequire"
)

func TestRegistry(t *testing.T) {
std.TestSetRealm(std.NewCodeRealm("gno.land/r/demo/foo"))
realmAddr := std.CurrentRealm().PkgPath()
token, ledger := grc20.NewToken("TestToken", "TST", 4)
ledger.Mint(std.CurrentRealm().Addr(), 1234567)
tokenGetter := func() *grc20.Token { return token }
// register
Register(tokenGetter, "")
regTokenGetter := Get(realmAddr)
regToken := regTokenGetter()
urequire.True(t, regToken != nil, "expected to find a token") // fixme: use urequire.NotNil
urequire.Equal(t, regToken.GetSymbol(), "TST")

expected := `- **TestToken** - [gno.land/r/demo/foo](/r/demo/foo) - [info](/r/demo/grc20reg:gno.land/r/demo/foo)
`
got := Render("")
urequire.True(t, strings.Contains(got, expected))
// 404
invalidToken := Get("0xdeadbeef")
urequire.True(t, invalidToken == nil)

// register with a slug
Register(tokenGetter, "mySlug")
regTokenGetter = Get(realmAddr + ".mySlug")
regToken = regTokenGetter()
urequire.True(t, regToken != nil, "expected to find a token") // fixme: use urequire.NotNil
urequire.Equal(t, regToken.GetSymbol(), "TST")

// override
Register(tokenGetter, "")
regTokenGetter = Get(realmAddr + "")
regToken = regTokenGetter()
urequire.True(t, regToken != nil, "expected to find a token") // fixme: use urequire.NotNil
urequire.Equal(t, regToken.GetSymbol(), "TST")

got = Render("")
urequire.True(t, strings.Contains(got, `- **TestToken** - [gno.land/r/demo/foo](/r/demo/foo) - [info](/r/demo/grc20reg:gno.land/r/demo/foo)`))
urequire.True(t, strings.Contains(got, `- **TestToken** - [gno.land/r/demo/foo](/r/demo/foo).mySlug - [info](/r/demo/grc20reg:gno.land/r/demo/foo.mySlug)`))

expected = `# TestToken
- symbol: **TST**
- realm: [gno.land/r/demo/foo](/r/demo/foo).mySlug
- decimals: 4
- total supply: 1234567
`
got = Render("gno.land/r/demo/foo.mySlug")
urequire.Equal(t, expected, got)
}
36 changes: 20 additions & 16 deletions __local/grc20_tokens/onbloc/bar/bar.gno
Original file line number Diff line number Diff line change
Expand Up @@ -7,54 +7,58 @@ import (
"gno.land/p/demo/ownable"
"gno.land/p/demo/ufmt"
pusers "gno.land/p/demo/users"

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

var (
admin *ownable.Ownable
token *grc20.Token
ledger *grc20.PrivateLedger
Token, privateLedger = grc20.NewToken("Bar", "BAR", 6)
UserTeller = Token.CallerTeller()
owner = ownable.NewWithAddress("g17290cwvmrapvp869xfnhhawa8sm9edpufzat7d") // ADMIN
)

func init() {
admin = ownable.NewWithAddress("g17290cwvmrapvp869xfnhhawa8sm9edpufzat7d") // ADMIN
token, ledger = grc20.NewToken("Bar", "BAR", 6)
ledger.Mint(admin.Owner(), 100_000_000_000_000)
privateLedger.Mint(owner.Owner(), 100_000_000_000_000)
getter := func() *grc20.Token { return Token }
grc20reg.Register(getter, "")
}

func TotalSupply() uint64 { return token.TotalSupply() }
func TotalSupply() uint64 {
return UserTeller.TotalSupply()
}

func BalanceOf(owner pusers.AddressOrName) uint64 {
ownerAddr := users.Resolve(owner)
return token.BalanceOf(ownerAddr)
return UserTeller.BalanceOf(ownerAddr)
}

func Allowance(owner, spender pusers.AddressOrName) uint64 {
ownerAddr := users.Resolve(owner)
spenderAddr := users.Resolve(spender)
return token.Allowance(ownerAddr, spenderAddr)
return UserTeller.Allowance(ownerAddr, spenderAddr)
}

func Transfer(to pusers.AddressOrName, amount uint64) {
toAddr := users.Resolve(to)
checkErr(token.CallerTeller().Transfer(toAddr, amount))
checkErr(UserTeller.Transfer(toAddr, amount))
}

func Approve(spender pusers.AddressOrName, amount uint64) {
spenderAddr := users.Resolve(spender)
checkErr(token.CallerTeller().Approve(spenderAddr, amount))
checkErr(UserTeller.Approve(spenderAddr, amount))
}

func TransferFrom(from, to pusers.AddressOrName, amount uint64) {
fromAddr := users.Resolve(from)
toAddr := users.Resolve(to)
checkErr(token.CallerTeller().TransferFrom(fromAddr, toAddr, amount))
checkErr(UserTeller.TransferFrom(fromAddr, toAddr, amount))
}

func Burn(from pusers.AddressOrName, amount uint64) {
admin.AssertCallerIsOwner()
owner.AssertCallerIsOwner()
fromAddr := users.Resolve(from)
checkErr(ledger.Burn(fromAddr, amount))
checkErr(privateLedger.Burn(fromAddr, amount))
}

func Render(path string) string {
Expand All @@ -63,11 +67,11 @@ func Render(path string) string {

switch {
case path == "":
return token.RenderHome()
return Token.RenderHome()
case c == 2 && parts[0] == "balance":
owner := pusers.AddressOrName(parts[1])
ownerAddr := users.Resolve(owner)
balance := token.BalanceOf(ownerAddr)
balance := UserTeller.BalanceOf(ownerAddr)
return ufmt.Sprintf("%d\n", balance)
default:
return "404\n"
Expand Down
1 change: 1 addition & 0 deletions __local/grc20_tokens/onbloc/bar/gno.mod
Original file line number Diff line number Diff line change
Expand Up @@ -6,4 +6,5 @@ require (
gno.land/p/demo/ufmt v0.0.0-latest
gno.land/p/demo/users v0.0.0-latest
gno.land/r/demo/users v0.0.0-latest
gno.land/r/demo/grc20reg v0.0.0-latest
)
36 changes: 20 additions & 16 deletions __local/grc20_tokens/onbloc/baz/baz.gno
Original file line number Diff line number Diff line change
Expand Up @@ -7,54 +7,58 @@ import (
"gno.land/p/demo/ownable"
"gno.land/p/demo/ufmt"
pusers "gno.land/p/demo/users"

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

var (
admin *ownable.Ownable
token *grc20.Token
ledger *grc20.PrivateLedger
Token, privateLedger = grc20.NewToken("Baz", "BAZ", 6)
UserTeller = Token.CallerTeller()
owner = ownable.NewWithAddress("g17290cwvmrapvp869xfnhhawa8sm9edpufzat7d") // ADMIN
)

func init() {
admin = ownable.NewWithAddress("g17290cwvmrapvp869xfnhhawa8sm9edpufzat7d") // ADMIN
token, ledger = grc20.NewToken("Baz", "BAZ", 6)
ledger.Mint(admin.Owner(), 100_000_000_000_000)
privateLedger.Mint(owner.Owner(), 100_000_000_000_000)
getter := func() *grc20.Token { return Token }
grc20reg.Register(getter, "")
}

func TotalSupply() uint64 { return token.TotalSupply() }
func TotalSupply() uint64 {
return UserTeller.TotalSupply()
}

func BalanceOf(owner pusers.AddressOrName) uint64 {
ownerAddr := users.Resolve(owner)
return token.BalanceOf(ownerAddr)
return UserTeller.BalanceOf(ownerAddr)
}

func Allowance(owner, spender pusers.AddressOrName) uint64 {
ownerAddr := users.Resolve(owner)
spenderAddr := users.Resolve(spender)
return token.Allowance(ownerAddr, spenderAddr)
return UserTeller.Allowance(ownerAddr, spenderAddr)
}

func Transfer(to pusers.AddressOrName, amount uint64) {
toAddr := users.Resolve(to)
checkErr(token.CallerTeller().Transfer(toAddr, amount))
checkErr(UserTeller.Transfer(toAddr, amount))
}

func Approve(spender pusers.AddressOrName, amount uint64) {
spenderAddr := users.Resolve(spender)
checkErr(token.CallerTeller().Approve(spenderAddr, amount))
checkErr(UserTeller.Approve(spenderAddr, amount))
}

func TransferFrom(from, to pusers.AddressOrName, amount uint64) {
fromAddr := users.Resolve(from)
toAddr := users.Resolve(to)
checkErr(token.CallerTeller().TransferFrom(fromAddr, toAddr, amount))
checkErr(UserTeller.TransferFrom(fromAddr, toAddr, amount))
}

func Burn(from pusers.AddressOrName, amount uint64) {
admin.AssertCallerIsOwner()
owner.AssertCallerIsOwner()
fromAddr := users.Resolve(from)
checkErr(ledger.Burn(fromAddr, amount))
checkErr(privateLedger.Burn(fromAddr, amount))
}

func Render(path string) string {
Expand All @@ -63,11 +67,11 @@ func Render(path string) string {

switch {
case path == "":
return token.RenderHome()
return Token.RenderHome()
case c == 2 && parts[0] == "balance":
owner := pusers.AddressOrName(parts[1])
ownerAddr := users.Resolve(owner)
balance := token.BalanceOf(ownerAddr)
balance := UserTeller.BalanceOf(ownerAddr)
return ufmt.Sprintf("%d\n", balance)
default:
return "404\n"
Expand Down
1 change: 1 addition & 0 deletions __local/grc20_tokens/onbloc/baz/gno.mod
Original file line number Diff line number Diff line change
Expand Up @@ -6,4 +6,5 @@ require (
gno.land/p/demo/ufmt v0.0.0-latest
gno.land/p/demo/users v0.0.0-latest
gno.land/r/demo/users v0.0.0-latest
gno.land/r/demo/grc20reg v0.0.0-latest
)
Loading