Nothing Special   »   [go: up one dir, main page]

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

feat: add grc20reg that works... today #3135

Open
wants to merge 20 commits into
base: master
Choose a base branch
from
2 changes: 1 addition & 1 deletion examples/Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -45,7 +45,7 @@ test:

.PHONY: lint
lint:
go run ../gnovm/cmd/gno lint $(OFFICIAL_PACKAGES)
go run ../gnovm/cmd/gno lint -v $(OFFICIAL_PACKAGES)

.PHONY: test.sync
test.sync:
Expand Down
41 changes: 28 additions & 13 deletions examples/gno.land/p/demo/grc/grc20/types.gno
Original file line number Diff line number Diff line change
Expand Up @@ -39,11 +39,11 @@ type Teller interface {
//
// Returns an error if the operation failed.
//
// IMPORTANT: Beware that changing an allowance with this method brings the risk
// that someone may use both the old and the new allowance by unfortunate
// transaction ordering. One possible solution to mitigate this race
// condition is to first reduce the spender's allowance to 0 and set the
// desired value afterwards:
// IMPORTANT: Beware that changing an allowance with this method brings
// the risk that someone may use both the old and the new allowance by
// unfortunate transaction ordering. One possible solution to mitigate
// this race condition is to first reduce the spender's allowance to 0
// and set the desired value afterwards:
// https://github.com/ethereum/EIPs/issues/20#issuecomment-263524729
Approve(spender std.Address, amount uint64) error

Expand All @@ -63,12 +63,23 @@ type Teller interface {
// name, symbol, and decimals, as well as methods for interacting with the
// ledger, including checking balances and allowances.
type Token struct {
name string // Name of the token (e.g., "Dummy Token").
symbol string // Symbol of the token (e.g., "DUMMY").
decimals uint // Number of decimal places used for the token's precision.
ledger *PrivateLedger // Pointer to the PrivateLedger that manages balances and allowances.
// Name of the token (e.g., "Dummy Token").
name string
// Symbol of the token (e.g., "DUMMY").
symbol string
// Number of decimal places used for the token's precision.
decimals uint
// Pointer to the PrivateLedger that manages balances and allowances.
ledger *PrivateLedger
}

// TokenGetter is a function type that returns a Token pointer. This type allows
// bypassing a limitation where we cannot directly pass Token pointers between
// realms. Instead, we pass this function which can then be called to get the
// Token pointer. For more details on this limitation and workaround, see:
// https://github.com/gnolang/gno/pull/3135
type TokenGetter func() *Token

// PrivateLedger is a struct that holds the balances and allowances for the
// token. It provides administrative functions for minting, burning,
// transferring tokens, and managing allowances.
Expand All @@ -77,10 +88,14 @@ type Token struct {
// information regarding token balances and allowances, and allows direct,
// unrestricted access to all administrative functions.
type PrivateLedger struct {
totalSupply uint64 // Total supply of the token managed by this ledger.
balances avl.Tree // std.Address -> uint64
allowances avl.Tree // owner.(std.Address)+":"+spender.(std.Address)) -> uint64
token *Token // Pointer to the associated Token struct
// Total supply of the token managed by this ledger.
totalSupply uint64
// std.Address -> uint64
balances avl.Tree
// owner.(std.Address)+":"+spender.(std.Address)) -> uint64
allowances avl.Tree
// Pointer to the associated Token struct
token *Token
}

var (
Expand Down
4 changes: 3 additions & 1 deletion examples/gno.land/r/demo/bar20/bar20.gno
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ import (

"gno.land/p/demo/grc/grc20"
"gno.land/p/demo/ufmt"
"gno.land/r/demo/grc20reg"
)

var (
Expand All @@ -17,7 +18,8 @@ var (
)

func init() {
// XXX: grc20reg.Register(Token, "")
getter := func() *grc20.Token { return Token }
grc20reg.Register(getter, "")
}

func Faucet() string {
Expand Down
1 change: 1 addition & 0 deletions examples/gno.land/r/demo/bar20/gno.mod
Original file line number Diff line number Diff line change
Expand Up @@ -5,4 +5,5 @@ require (
gno.land/p/demo/testutils v0.0.0-latest
gno.land/p/demo/ufmt v0.0.0-latest
gno.land/p/demo/urequire v0.0.0-latest
gno.land/r/demo/grc20reg v0.0.0-latest
)
4 changes: 3 additions & 1 deletion examples/gno.land/r/demo/foo20/foo20.gno
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ 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"
)

Expand All @@ -21,7 +22,8 @@ var (

func init() {
privateLedger.Mint(owner.Owner(), 1_000_000*10_000) // @privateLedgeristrator (1M)
// XXX: grc20reg.Register(Token, "")
getter := func() *grc20.Token { return Token }
grc20reg.Register(getter, "")
}

func TotalSupply() uint64 {
Expand Down
1 change: 1 addition & 0 deletions examples/gno.land/r/demo/foo20/gno.mod
Original file line number Diff line number Diff line change
Expand Up @@ -7,5 +7,6 @@ require (
gno.land/p/demo/uassert v0.0.0-latest
gno.land/p/demo/ufmt v0.0.0-latest
gno.land/p/demo/users v0.0.0-latest
gno.land/r/demo/grc20reg v0.0.0-latest
gno.land/r/demo/users v0.0.0-latest
)
1 change: 1 addition & 0 deletions examples/gno.land/r/demo/grc20factory/gno.mod
Original file line number Diff line number Diff line change
Expand Up @@ -7,4 +7,5 @@ require (
gno.land/p/demo/testutils v0.0.0-latest
gno.land/p/demo/uassert v0.0.0-latest
gno.land/p/demo/ufmt v0.0.0-latest
gno.land/r/demo/grc20reg v0.0.0-latest
)
4 changes: 3 additions & 1 deletion examples/gno.land/r/demo/grc20factory/grc20factory.gno
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ import (
"gno.land/p/demo/grc/grc20"
"gno.land/p/demo/ownable"
"gno.land/p/demo/ufmt"
"gno.land/r/demo/grc20reg"
)

var instances avl.Tree // symbol -> instance
Expand Down Expand Up @@ -42,7 +43,8 @@ func NewWithAdmin(name, symbol string, decimals uint, initialMint, faucet uint64
faucet: faucet,
}
instances.Set(symbol, &inst)
// XXX: grc20reg.Register(token, symbol)
getter := func() *grc20.Token { return token }
grc20reg.Register(getter, symbol)
}

func (inst instance) Token() *grc20.Token {
Expand Down
9 changes: 9 additions & 0 deletions examples/gno.land/r/demo/grc20reg/gno.mod
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
module gno.land/r/demo/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 examples/gno.land/r/demo/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"
60 changes: 60 additions & 0 deletions examples/gno.land/r/demo/grc20reg/grc20reg_test.gno
Original file line number Diff line number Diff line change
@@ -0,0 +1,60 @@
package grc20reg

import (
"std"
"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.Equal(t, expected, got)
// 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")

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

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)
}
28 changes: 28 additions & 0 deletions examples/gno.land/r/demo/tests/crossrealm/crossrealm.gno
Original file line number Diff line number Diff line change
Expand Up @@ -27,3 +27,31 @@ func Make1() *p_crossrealm.Container {
B: local,
}
}

type Fooer interface{ Foo() }

var fooer Fooer

func SetFooer(f Fooer) Fooer {
fooer = f
return fooer
}

func GetFooer() Fooer { return fooer }

func CallFooerFoo() { fooer.Foo() }

type FooerGetter func() Fooer

var fooerGetter FooerGetter

func SetFooerGetter(fg FooerGetter) FooerGetter {
fooerGetter = fg
return fg
}

func GetFooerGetter() FooerGetter {
return fooerGetter
}

func CallFooerGetterFoo() { fooerGetter().Foo() }
25 changes: 25 additions & 0 deletions examples/gno.land/r/demo/tests/crossrealm_b/crossrealm.gno
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
package crossrealm_b

import (
"std"

"gno.land/r/demo/tests/crossrealm"
)

type fooer struct {
s string
}

func (f *fooer) SetS(newVal string) {
f.s = newVal
}

func (f *fooer) Foo() {
println("hello " + f.s + " cur=" + std.CurrentRealm().PkgPath() + " prev=" + std.PrevRealm().PkgPath())
}

var (
Fooer = &fooer{s: "A"}
FooerGetter = func() crossrealm.Fooer { return Fooer }
FooerGetterBuilder = func() crossrealm.FooerGetter { return func() crossrealm.Fooer { return Fooer } }
)
3 changes: 3 additions & 0 deletions examples/gno.land/r/demo/tests/crossrealm_b/gno.mod
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
module gno.land/r/demo/tests/crossrealm_b

require gno.land/r/demo/tests/crossrealm v0.0.0-latest
2 changes: 2 additions & 0 deletions examples/gno.land/r/demo/tests/tests.gno
Original file line number Diff line number Diff line change
Expand Up @@ -50,6 +50,8 @@ type TestRealmObject struct {
Field string
}

var TestRealmObjectValue TestRealmObject

func ModifyTestRealmObject(t *TestRealmObject) {
t.Field += "_modified"
}
Expand Down
1 change: 1 addition & 0 deletions examples/gno.land/r/demo/wugnot/gno.mod
Original file line number Diff line number Diff line change
Expand Up @@ -4,5 +4,6 @@ require (
gno.land/p/demo/grc/grc20 v0.0.0-latest
gno.land/p/demo/ufmt v0.0.0-latest
gno.land/p/demo/users v0.0.0-latest
gno.land/r/demo/grc20reg v0.0.0-latest
gno.land/r/demo/users v0.0.0-latest
)
4 changes: 3 additions & 1 deletion examples/gno.land/r/demo/wugnot/wugnot.gno
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ import (
"gno.land/p/demo/grc/grc20"
"gno.land/p/demo/ufmt"
pusers "gno.land/p/demo/users"
"gno.land/r/demo/grc20reg"
"gno.land/r/demo/users"
)

Expand All @@ -18,7 +19,8 @@ const (
)

func init() {
// XXX: grc20reg.Register(Token, "")
getter := func() *grc20.Token { return Token }
grc20reg.Register(getter, "")
}

func Deposit() {
Expand Down
Loading
Loading