From 4b6ef9c0290e16036cfc4593194a2baee432dfe1 Mon Sep 17 00:00:00 2001 From: n3wbie Date: Sat, 21 Oct 2023 10:19:28 -0400 Subject: [PATCH 1/8] feat: call grc20 function with registered interface(without import) --- .../r/x/grc20_dynamic_call/bar/bar.gno | 130 ++++++++++++++ .../r/x/grc20_dynamic_call/bar/gno.mod | 1 + .../r/x/grc20_dynamic_call/baz/baz.gno | 130 ++++++++++++++ .../r/x/grc20_dynamic_call/baz/gno.mod | 1 + .../r/x/grc20_dynamic_call/foo/foo.gno | 130 ++++++++++++++ .../r/x/grc20_dynamic_call/foo/gno.mod | 1 + .../r/x/grc20_dynamic_call/registry/gno.mod | 1 + .../grc20_dynamic_call/registry/registry.gno | 101 +++++++++++ .../registry/registry_test.gno | 163 ++++++++++++++++++ .../r/x/grc20_dynamic_call/wrapper/gno.mod | 1 + .../x/grc20_dynamic_call/wrapper/wrapper.gno | 65 +++++++ 11 files changed, 724 insertions(+) create mode 100644 examples/gno.land/r/x/grc20_dynamic_call/bar/bar.gno create mode 100644 examples/gno.land/r/x/grc20_dynamic_call/bar/gno.mod create mode 100644 examples/gno.land/r/x/grc20_dynamic_call/baz/baz.gno create mode 100644 examples/gno.land/r/x/grc20_dynamic_call/baz/gno.mod create mode 100644 examples/gno.land/r/x/grc20_dynamic_call/foo/foo.gno create mode 100644 examples/gno.land/r/x/grc20_dynamic_call/foo/gno.mod create mode 100644 examples/gno.land/r/x/grc20_dynamic_call/registry/gno.mod create mode 100644 examples/gno.land/r/x/grc20_dynamic_call/registry/registry.gno create mode 100644 examples/gno.land/r/x/grc20_dynamic_call/registry/registry_test.gno create mode 100644 examples/gno.land/r/x/grc20_dynamic_call/wrapper/gno.mod create mode 100644 examples/gno.land/r/x/grc20_dynamic_call/wrapper/wrapper.gno diff --git a/examples/gno.land/r/x/grc20_dynamic_call/bar/bar.gno b/examples/gno.land/r/x/grc20_dynamic_call/bar/bar.gno new file mode 100644 index 00000000000..1638971f63d --- /dev/null +++ b/examples/gno.land/r/x/grc20_dynamic_call/bar/bar.gno @@ -0,0 +1,130 @@ +package bar + +import ( + "std" + "strings" + + "gno.land/p/demo/grc/grc20" + "gno.land/p/demo/ufmt" + "gno.land/r/demo/users" +) + +var ( + bar *grc20.AdminToken + admin std.Address = "g1us8428u2a5satrlxzagqqa5m6vmuze025anjlj" // TODO: helper to change admin +) + +func init() { + bar = grc20.NewAdminToken("Bar", "BAR", 4) + bar.Mint(admin, 1000000*10000) // @administrator (1M) + bar.Mint("g1u7y667z64x2h7vc6fmpcprgey4ck233jaww9zq", 10000*10000) // @manfred (10k) +} + +// method proxies as public functions. +// + +// getters. + +func TotalSupply() uint64 { + return bar.TotalSupply() +} + +func BalanceOf(owner users.AddressOrName) uint64 { + balance, err := bar.BalanceOf(owner.Resolve()) + if err != nil { + panic(err) + } + return balance +} + +func Allowance(owner, spender users.AddressOrName) uint64 { + allowance, err := bar.Allowance(owner.Resolve(), spender.Resolve()) + if err != nil { + panic(err) + } + return allowance +} + +// setters. + +func Transfer(to users.AddressOrName, amount uint64) { + caller := std.PrevRealm().Addr() + err := bar.Transfer(caller, to.Resolve(), amount) + if err != nil { + panic(err) + } +} + +func Approve(spender users.AddressOrName, amount uint64) { + // caller := std.PrevRealm().Addr() + caller := std.GetOrigCaller() + err := bar.Approve(caller, spender.Resolve(), amount) + if err != nil { + panic(err) + } +} + +func TransferFrom(from, to users.AddressOrName, amount uint64) { + caller := std.PrevRealm().Addr() + err := bar.TransferFrom(caller, from.Resolve(), to.Resolve(), amount) + if err != nil { + panic(err) + } +} + +// faucet. + +func Faucet() { + // FIXME: add limits? + // FIXME: add payment in gnot? + caller := std.PrevRealm().Addr() + err := bar.Mint(caller, 1000*10000) // 1k + if err != nil { + panic(err) + } +} + +// administration. + +func Mint(address users.AddressOrName, amount uint64) { + caller := std.PrevRealm().Addr() + assertIsAdmin(caller) + err := bar.Mint(address.Resolve(), amount) + if err != nil { + panic(err) + } +} + +func Burn(address users.AddressOrName, amount uint64) { + caller := std.PrevRealm().Addr() + assertIsAdmin(caller) + err := bar.Burn(address.Resolve(), amount) + if err != nil { + panic(err) + } +} + +// render. +// + +func Render(path string) string { + parts := strings.Split(path, "/") + c := len(parts) + + switch { + case path == "": + return bar.RenderHome() + case c == 2 && parts[0] == "balance": + owner := users.AddressOrName(parts[1]) + balance, _ := bar.BalanceOf(owner.Resolve()) + return ufmt.Sprintf("%d\n", balance) + default: + return "404\n" + } +} + +func assertIsAdmin(address std.Address) { + if address != admin { + panic("restricted access") + } +} diff --git a/examples/gno.land/r/x/grc20_dynamic_call/bar/gno.mod b/examples/gno.land/r/x/grc20_dynamic_call/bar/gno.mod new file mode 100644 index 00000000000..25d8df533cb --- /dev/null +++ b/examples/gno.land/r/x/grc20_dynamic_call/bar/gno.mod @@ -0,0 +1 @@ +module gno.land/r/x/grc20_dynamic_call/bar \ No newline at end of file diff --git a/examples/gno.land/r/x/grc20_dynamic_call/baz/baz.gno b/examples/gno.land/r/x/grc20_dynamic_call/baz/baz.gno new file mode 100644 index 00000000000..f0393edac52 --- /dev/null +++ b/examples/gno.land/r/x/grc20_dynamic_call/baz/baz.gno @@ -0,0 +1,130 @@ +package baz + +import ( + "std" + "strings" + + "gno.land/p/demo/grc/grc20" + "gno.land/p/demo/ufmt" + "gno.land/r/demo/users" +) + +var ( + baz *grc20.AdminToken + admin std.Address = "g1us8428u2a5satrlxzagqqa5m6vmuze025anjlj" // TODO: helper to change admin +) + +func init() { + baz = grc20.NewAdminToken("Baz", "BAZ", 4) + baz.Mint(admin, 1000000*10000) // @administrator (1M) + baz.Mint("g1u7y667z64x2h7vc6fmpcprgey4ck233jaww9zq", 10000*10000) // @manfred (10k) +} + +// method proxies as public functions. +// + +// getters. + +func TotalSupply() uint64 { + return baz.TotalSupply() +} + +func BalanceOf(owner users.AddressOrName) uint64 { + balance, err := baz.BalanceOf(owner.Resolve()) + if err != nil { + panic(err) + } + return balance +} + +func Allowance(owner, spender users.AddressOrName) uint64 { + allowance, err := baz.Allowance(owner.Resolve(), spender.Resolve()) + if err != nil { + panic(err) + } + return allowance +} + +// setters. + +func Transfer(to users.AddressOrName, amount uint64) { + caller := std.PrevRealm().Addr() + err := baz.Transfer(caller, to.Resolve(), amount) + if err != nil { + panic(err) + } +} + +func Approve(spender users.AddressOrName, amount uint64) { + // caller := std.PrevRealm().Addr() + caller := std.GetOrigCaller() + err := baz.Approve(caller, spender.Resolve(), amount) + if err != nil { + panic(err) + } +} + +func TransferFrom(from, to users.AddressOrName, amount uint64) { + caller := std.PrevRealm().Addr() + err := baz.TransferFrom(caller, from.Resolve(), to.Resolve(), amount) + if err != nil { + panic(err) + } +} + +// faucet. + +func Faucet() { + // FIXME: add limits? + // FIXME: add payment in gnot? + caller := std.PrevRealm().Addr() + err := baz.Mint(caller, 1000*10000) // 1k + if err != nil { + panic(err) + } +} + +// administration. + +func Mint(address users.AddressOrName, amount uint64) { + caller := std.PrevRealm().Addr() + assertIsAdmin(caller) + err := baz.Mint(address.Resolve(), amount) + if err != nil { + panic(err) + } +} + +func Burn(address users.AddressOrName, amount uint64) { + caller := std.PrevRealm().Addr() + assertIsAdmin(caller) + err := baz.Burn(address.Resolve(), amount) + if err != nil { + panic(err) + } +} + +// render. +// + +func Render(path string) string { + parts := strings.Split(path, "/") + c := len(parts) + + switch { + case path == "": + return baz.RenderHome() + case c == 2 && parts[0] == "balance": + owner := users.AddressOrName(parts[1]) + balance, _ := baz.BalanceOf(owner.Resolve()) + return ufmt.Sprintf("%d\n", balance) + default: + return "404\n" + } +} + +func assertIsAdmin(address std.Address) { + if address != admin { + panic("restricted access") + } +} diff --git a/examples/gno.land/r/x/grc20_dynamic_call/baz/gno.mod b/examples/gno.land/r/x/grc20_dynamic_call/baz/gno.mod new file mode 100644 index 00000000000..08cc2052e2c --- /dev/null +++ b/examples/gno.land/r/x/grc20_dynamic_call/baz/gno.mod @@ -0,0 +1 @@ +module gno.land/r/x/grc20_dynamic_call/baz \ No newline at end of file diff --git a/examples/gno.land/r/x/grc20_dynamic_call/foo/foo.gno b/examples/gno.land/r/x/grc20_dynamic_call/foo/foo.gno new file mode 100644 index 00000000000..7377bdc744c --- /dev/null +++ b/examples/gno.land/r/x/grc20_dynamic_call/foo/foo.gno @@ -0,0 +1,130 @@ +package foo + +import ( + "std" + "strings" + + "gno.land/p/demo/grc/grc20" + "gno.land/p/demo/ufmt" + "gno.land/r/demo/users" +) + +var ( + foo *grc20.AdminToken + admin std.Address = "g1us8428u2a5satrlxzagqqa5m6vmuze025anjlj" // TODO: helper to change admin +) + +func init() { + foo = grc20.NewAdminToken("Foo", "FOO", 4) + foo.Mint(admin, 1000000*10000) // @administrator (1M) + foo.Mint("g1u7y667z64x2h7vc6fmpcprgey4ck233jaww9zq", 10000*10000) // @manfred (10k) +} + +// method proxies as public functions. +// + +// getters. + +func TotalSupply() uint64 { + return foo.TotalSupply() +} + +func BalanceOf(owner users.AddressOrName) uint64 { + balance, err := foo.BalanceOf(owner.Resolve()) + if err != nil { + panic(err) + } + return balance +} + +func Allowance(owner, spender users.AddressOrName) uint64 { + allowance, err := foo.Allowance(owner.Resolve(), spender.Resolve()) + if err != nil { + panic(err) + } + return allowance +} + +// setters. + +func Transfer(to users.AddressOrName, amount uint64) { + caller := std.PrevRealm().Addr() + err := foo.Transfer(caller, to.Resolve(), amount) + if err != nil { + panic(err) + } +} + +func Approve(spender users.AddressOrName, amount uint64) { + // caller := std.PrevRealm().Addr() + caller := std.GetOrigCaller() + err := foo.Approve(caller, spender.Resolve(), amount) + if err != nil { + panic(err) + } +} + +func TransferFrom(from, to users.AddressOrName, amount uint64) { + caller := std.PrevRealm().Addr() + err := foo.TransferFrom(caller, from.Resolve(), to.Resolve(), amount) + if err != nil { + panic(err) + } +} + +// faucet. + +func Faucet() { + // FIXME: add limits? + // FIXME: add payment in gnot? + caller := std.PrevRealm().Addr() + err := foo.Mint(caller, 1000*10000) // 1k + if err != nil { + panic(err) + } +} + +// administration. + +func Mint(address users.AddressOrName, amount uint64) { + caller := std.PrevRealm().Addr() + assertIsAdmin(caller) + err := foo.Mint(address.Resolve(), amount) + if err != nil { + panic(err) + } +} + +func Burn(address users.AddressOrName, amount uint64) { + caller := std.PrevRealm().Addr() + assertIsAdmin(caller) + err := foo.Burn(address.Resolve(), amount) + if err != nil { + panic(err) + } +} + +// render. +// + +func Render(path string) string { + parts := strings.Split(path, "/") + c := len(parts) + + switch { + case path == "": + return foo.RenderHome() + case c == 2 && parts[0] == "balance": + owner := users.AddressOrName(parts[1]) + balance, _ := foo.BalanceOf(owner.Resolve()) + return ufmt.Sprintf("%d\n", balance) + default: + return "404\n" + } +} + +func assertIsAdmin(address std.Address) { + if address != admin { + panic("restricted access") + } +} diff --git a/examples/gno.land/r/x/grc20_dynamic_call/foo/gno.mod b/examples/gno.land/r/x/grc20_dynamic_call/foo/gno.mod new file mode 100644 index 00000000000..c19f0909246 --- /dev/null +++ b/examples/gno.land/r/x/grc20_dynamic_call/foo/gno.mod @@ -0,0 +1 @@ +module gno.land/r/x/grc20_dynamic_call/foo \ No newline at end of file diff --git a/examples/gno.land/r/x/grc20_dynamic_call/registry/gno.mod b/examples/gno.land/r/x/grc20_dynamic_call/registry/gno.mod new file mode 100644 index 00000000000..eae8c464276 --- /dev/null +++ b/examples/gno.land/r/x/grc20_dynamic_call/registry/gno.mod @@ -0,0 +1 @@ +module gno.land/r/x/grc20_dynamic_call/registry \ No newline at end of file diff --git a/examples/gno.land/r/x/grc20_dynamic_call/registry/registry.gno b/examples/gno.land/r/x/grc20_dynamic_call/registry/registry.gno new file mode 100644 index 00000000000..ebf0dc72215 --- /dev/null +++ b/examples/gno.land/r/x/grc20_dynamic_call/registry/registry.gno @@ -0,0 +1,101 @@ +package registry + +import ( + "std" + + "gno.land/r/demo/users" +) + +const APPROVED_UNREGISTER_CALLER = "g1sqt92sa06ugh8nlt98kyghw83qy84paf4csyh6" + +var registered = []GRC20Pair{} + +type GRC20Interface interface { + Transfer() func(to users.AddressOrName, amount uint64) + TransferFrom() func(from, to users.AddressOrName, amount uint64) + BalanceOf() func(owner users.AddressOrName) uint64 +} + +type GRC20Pair struct { + pkgPath string + igrc20 GRC20Interface +} + +func findGRC20(pkgPath string) (int, bool) { + for i, pair := range registered { + if pair.pkgPath == pkgPath { + return i, true + } + } + + return -1, false +} + +func appendGRC20Interface(pkgPath string, igrc20 GRC20Interface) { + registered = append(registered, GRC20Pair{pkgPath: pkgPath, igrc20: igrc20}) +} + +func removeGRC20Interface(pkgPath string) { + i, found := findGRC20(pkgPath) + if !found { + return + } + + registered = append(registered[:i], registered[i+1:]...) +} + +func RegisterGRC20Interface(pkgPath string, igrc20 GRC20Interface) { + _, found := findGRC20(pkgPath) + if found { + panic("GRC20 already registered") + } + + appendGRC20Interface(pkgPath, igrc20) +} + +func UnregisterGRC20Interface(pkgPath string) { + // do not allow realm to unregister + std.AssertOriginCall() + caller := std.GetOrigCaller() + + if caller != APPROVED_UNREGISTER_CALLER { + panic("unauthorized") + } + + _, found := findGRC20(pkgPath) + if found { + removeGRC20Interface(pkgPath) + } +} + +func TransferByInterfaceName(pkgPath string, to string, amount uint64) bool { + i, found := findGRC20(pkgPath) + if !found { + return false + } + + registered[i].igrc20.Transfer()(users.AddressOrName(to), amount) + + return true +} + +func TransferFromByInterfaceName(pkgPath string, from, to string, amount uint64) bool { + i, found := findGRC20(pkgPath) + if !found { + return false + } + + registered[i].igrc20.TransferFrom()(users.AddressOrName(from), users.AddressOrName(to), amount) + + return true +} + +func BalanceOfByInterfaceName(pkgPath string, owner string) uint64 { + i, found := findGRC20(pkgPath) + if !found { + return 0 + } + + balance := registered[i].igrc20.BalanceOf()(users.AddressOrName(owner)) + return balance +} diff --git a/examples/gno.land/r/x/grc20_dynamic_call/registry/registry_test.gno b/examples/gno.land/r/x/grc20_dynamic_call/registry/registry_test.gno new file mode 100644 index 00000000000..a3b0fb5c963 --- /dev/null +++ b/examples/gno.land/r/x/grc20_dynamic_call/registry/registry_test.gno @@ -0,0 +1,163 @@ +package registry + +import ( + "std" + "testing" + + "gno.land/r/x/grc20_dynamic_call/bar" + "gno.land/r/x/grc20_dynamic_call/baz" + "gno.land/r/x/grc20_dynamic_call/foo" + + "gno.land/r/demo/users" + + _ "gno.land/r/x/grc20_dynamic_call/wrapper" +) + +const ( + transferTo string = "g12345" + + transferFromFrom string = "g12345" + transferFromTo string = "g54321" +) + +var cRealmAddr std.Address + +func init() { + cRealmAddr = std.CurrentRealm().Addr() + + std.TestSetOrigCaller(cRealmAddr) + foo.Faucet() + bar.Faucet() + baz.Faucet() +} + +func TestTransferByNameFOO(t *testing.T) { + fooBalance := BalanceOfByInterfaceName("gno.land/r/x/grc20_dynamic_call/foo", transferTo) + if fooBalance != 0 { + t.Fatal("transferTo should have 0 FOO but", fooBalance) + } + + TransferByInterfaceName("gno.land/r/x/grc20_dynamic_call/foo", transferTo, 12345) + + fooBalance = BalanceOfByInterfaceName("gno.land/r/x/grc20_dynamic_call/foo", transferTo) + if fooBalance != 12345 { + t.Fatal("transferTo should have 12345 FOO, but", fooBalance) + } +} + +func TestTransferByNameBAR(t *testing.T) { + barBalance := BalanceOfByInterfaceName("gno.land/r/x/grc20_dynamic_call/bar", transferTo) + if barBalance != 0 { + t.Fatal("transferTo should have 0 BAR but", barBalance) + } + + TransferByInterfaceName("gno.land/r/x/grc20_dynamic_call/bar", transferTo, 12345) + + barBalance = BalanceOfByInterfaceName("gno.land/r/x/grc20_dynamic_call/bar", transferTo) + if barBalance != 12345 { + t.Fatal("transferTo should have 12345 BAR, but", barBalance) + } +} + +func TestTransferByNameBAZ(t *testing.T) { + bazBalance := BalanceOfByInterfaceName("gno.land/r/x/grc20_dynamic_call/baz", transferTo) + if bazBalance != 0 { + t.Fatal("transferTo should have 0 BAZ but", bazBalance) + } + + TransferByInterfaceName("gno.land/r/x/grc20_dynamic_call/baz", transferTo, 12345) + + bazBalance = BalanceOfByInterfaceName("gno.land/r/x/grc20_dynamic_call/baz", transferTo) + if bazBalance != 12345 { + t.Fatal("transferTo should have 12345 BAZ, but", bazBalance) + } +} + +func TestTransferFromByNameFOO(t *testing.T) { + fooBalanceTo := BalanceOfByInterfaceName("gno.land/r/x/grc20_dynamic_call/foo", transferFromTo) + if fooBalanceTo != 0 { + t.Fatal("transferFromTo should have 0 FOO, but", fooBalanceTo) + } + + std.TestSetOrigCaller(transferFromFrom) + foo.Approve(users.AddressOrName(cRealmAddr), 5) + TransferFromByInterfaceName("gno.land/r/x/grc20_dynamic_call/foo", transferFromFrom, transferFromTo, 3) + + fooBalanceTo = BalanceOfByInterfaceName("gno.land/r/x/grc20_dynamic_call/foo", transferFromTo) + if fooBalanceTo != 3 { + t.Fatal("transferFromTo should have 3 FOO, but", fooBalanceTo) + } + + fooBalanceFrom := BalanceOfByInterfaceName("gno.land/r/x/grc20_dynamic_call/foo", transferFromFrom) + if fooBalanceFrom != 12342 { + t.Fatal("transferFromFrom should have 12342 FOO, but", fooBalanceFrom) + } +} + +func TestTransferFromByNameBAR(t *testing.T) { + barBalanceTo := BalanceOfByInterfaceName("gno.land/r/x/grc20_dynamic_call/bar", transferFromTo) + if barBalanceTo != 0 { + t.Fatal("transferFromTo should have 0 BAR, but", barBalanceTo) + } + + std.TestSetOrigCaller(transferFromFrom) + bar.Approve(users.AddressOrName(cRealmAddr), 5) + TransferFromByInterfaceName("gno.land/r/x/grc20_dynamic_call/bar", transferFromFrom, transferFromTo, 3) + + barBalanceTo = BalanceOfByInterfaceName("gno.land/r/x/grc20_dynamic_call/bar", transferFromTo) + if barBalanceTo != 3 { + t.Fatal("transferFromTo should have 3 BAR, but", barBalanceTo) + } + + barBalanceFrom := BalanceOfByInterfaceName("gno.land/r/x/grc20_dynamic_call/bar", transferFromFrom) + if barBalanceFrom != 12342 { + t.Fatal("transferFromFrom should have 12342 BAR, but", barBalanceFrom) + } +} + +func TestTransferFromByNameBAZ(t *testing.T) { + bazBalanceTo := BalanceOfByInterfaceName("gno.land/r/x/grc20_dynamic_call/baz", transferFromTo) + if bazBalanceTo != 0 { + t.Fatal("transferFromTo should have 0 BAZ, but", bazBalanceTo) + } + + std.TestSetOrigCaller(transferFromFrom) + baz.Approve(users.AddressOrName(cRealmAddr), 5) + TransferFromByInterfaceName("gno.land/r/x/grc20_dynamic_call/baz", transferFromFrom, transferFromTo, 3) + + bazBalanceTo = BalanceOfByInterfaceName("gno.land/r/x/grc20_dynamic_call/baz", transferFromTo) + if bazBalanceTo != 3 { + t.Fatal("transferFromTo should have 3 BAZ, but", bazBalanceTo) + } + + bazBalanceFrom := BalanceOfByInterfaceName("gno.land/r/x/grc20_dynamic_call/baz", transferFromFrom) + if bazBalanceFrom != 12342 { + t.Fatal("transferFromFrom should have 12342 BAZ, but", bazBalanceFrom) + } +} + +func TestUnregisterUnauthorized(t *testing.T) { + shouldPanic(t, func() { UnregisterGRC20Interface("gno.land/r/x/grc20_dynamic_call/foo") }) +} + +func TestUnregisterAuthorized(t *testing.T) { + if len(registered) != 3 { + t.Fatal("should have 3 registered interfaces but", len(registered)) + } + + std.TestSetOrigCaller("g1sqt92sa06ugh8nlt98kyghw83qy84paf4csyh6") + UnregisterGRC20Interface("gno.land/r/x/grc20_dynamic_call/foo") + + if len(registered) != 2 { + t.Fatal("should have 2 registered interfaces") + } +} + +func shouldPanic(t *testing.T, f func()) { + defer func() { + if r := recover(); r == nil { + t.Errorf("expected panic") + } + }() + f() +} diff --git a/examples/gno.land/r/x/grc20_dynamic_call/wrapper/gno.mod b/examples/gno.land/r/x/grc20_dynamic_call/wrapper/gno.mod new file mode 100644 index 00000000000..a802235087a --- /dev/null +++ b/examples/gno.land/r/x/grc20_dynamic_call/wrapper/gno.mod @@ -0,0 +1 @@ +module gno.land/r/x/grc20_dynamic_call/wrapper \ No newline at end of file diff --git a/examples/gno.land/r/x/grc20_dynamic_call/wrapper/wrapper.gno b/examples/gno.land/r/x/grc20_dynamic_call/wrapper/wrapper.gno new file mode 100644 index 00000000000..6c81c9a6d2e --- /dev/null +++ b/examples/gno.land/r/x/grc20_dynamic_call/wrapper/wrapper.gno @@ -0,0 +1,65 @@ +package wrapper + +import ( + "gno.land/r/demo/users" + + "gno.land/r/x/grc20_dynamic_call/bar" + "gno.land/r/x/grc20_dynamic_call/baz" + "gno.land/r/x/grc20_dynamic_call/foo" + + "gno.land/r/x/grc20_dynamic_call/registry" +) + +type FooTokenInterface struct{} + +func (FooTokenInterface) Transfer() func(to users.AddressOrName, amount uint64) { + return foo.Transfer +} + +func (FooTokenInterface) TransferFrom() func(from, to users.AddressOrName, amount uint64) { + return foo.TransferFrom +} + +func (FooTokenInterface) BalanceOf() func(owner users.AddressOrName) uint64 { + return foo.BalanceOf +} + +var _ registry.GRC20Interface = FooTokenInterface{} + +type BarTokenInterface struct{} + +func (BarTokenInterface) Transfer() func(to users.AddressOrName, amount uint64) { + return bar.Transfer +} + +func (BarTokenInterface) TransferFrom() func(from, to users.AddressOrName, amount uint64) { + return bar.TransferFrom +} + +func (BarTokenInterface) BalanceOf() func(owner users.AddressOrName) uint64 { + return bar.BalanceOf +} + +var _ registry.GRC20Interface = BarTokenInterface{} + +type BazTokenInterface struct{} + +func (BazTokenInterface) Transfer() func(to users.AddressOrName, amount uint64) { + return baz.Transfer +} + +func (BazTokenInterface) TransferFrom() func(from, to users.AddressOrName, amount uint64) { + return baz.TransferFrom +} + +func (BazTokenInterface) BalanceOf() func(owner users.AddressOrName) uint64 { + return baz.BalanceOf +} + +var _ registry.GRC20Interface = BazTokenInterface{} + +func init() { + registry.RegisterGRC20Interface("gno.land/r/x/grc20_dynamic_call/foo", FooTokenInterface{}) + registry.RegisterGRC20Interface("gno.land/r/x/grc20_dynamic_call/bar", BarTokenInterface{}) + registry.RegisterGRC20Interface("gno.land/r/x/grc20_dynamic_call/baz", BazTokenInterface{}) +} From cfeda1d4077bdefb824959f7cc581f76d6b6466a Mon Sep 17 00:00:00 2001 From: n3wbie Date: Sat, 21 Oct 2023 11:15:31 -0400 Subject: [PATCH 2/8] feat: add txtar --- .../cmd/gnoland/testdata/grc20_dynamic.txtar | 21 +++++++++++++++++++ 1 file changed, 21 insertions(+) create mode 100644 gno.land/cmd/gnoland/testdata/grc20_dynamic.txtar diff --git a/gno.land/cmd/gnoland/testdata/grc20_dynamic.txtar b/gno.land/cmd/gnoland/testdata/grc20_dynamic.txtar new file mode 100644 index 00000000000..6756ae5f0ca --- /dev/null +++ b/gno.land/cmd/gnoland/testdata/grc20_dynamic.txtar @@ -0,0 +1,21 @@ +# test for calling grc20 token's function with registering interface + +## start gnoland node +gnoland start + +## faucet foo token by test1 +gnokey maketx call -pkgpath gno.land/r/x/grc20_dynamic_call/foo -func Faucet -gas-fee 1000000ugnot -gas-wanted 2000000 -broadcast -chainid=tendermint_test test1 + +## check test1 foo balance +gnokey maketx call -pkgpath gno.land/r/x/grc20_dynamic_call/registry -func BalanceOfByInterfaceName -args 'gno.land/r/x/grc20_dynamic_call/foo' -args 'g1jg8mtutu9khhfwc4nxmuhcpftf0pajdhfvsqf5' -gas-fee 1000000ugnot -gas-wanted 2000000 -broadcast -chainid=tendermint_test test1 +stdout '(10000000 uint64)' + +## approve +gnokey maketx call -pkgpath gno.land/r/x/grc20_dynamic_call/foo -func Approve -args 'g1tkmrcu9m0xjddxh0c29r3zac8m2yjwaytlvh6u' -args '12345' -gas-fee 1000000ugnot -gas-wanted 2000000 -broadcast -chainid=tendermint_test test1 + +## transferFrom foo token using registered interface +gnokey maketx call -pkgpath gno.land/r/x/grc20_dynamic_call/registry -func TransferFromByInterfaceName -args 'gno.land/r/x/grc20_dynamic_call/foo' -args 'g1jg8mtutu9khhfwc4nxmuhcpftf0pajdhfvsqf5' -args 'g12345' -args '12345' -gas-fee 1000000ugnot -gas-wanted 2000000 -broadcast -chainid=tendermint_test test1 + +## check balance after TransferByInterfaceName +gnokey maketx call -pkgpath gno.land/r/x/grc20_dynamic_call/registry -func BalanceOfByInterfaceName -args 'gno.land/r/x/grc20_dynamic_call/foo' -args 'g1jg8mtutu9khhfwc4nxmuhcpftf0pajdhfvsqf5' -gas-fee 1000000ugnot -gas-wanted 2000000 -broadcast -chainid=tendermint_test test1 +stdout '(9987655 uint64)' \ No newline at end of file From 0075529d396653d0f46d980957ec08ea1c534673 Mon Sep 17 00:00:00 2001 From: n3wbie Date: Thu, 7 Dec 2023 14:08:05 +0900 Subject: [PATCH 3/8] chore: update `gno.mod` --- examples/gno.land/r/x/grc20_dynamic_call/bar/gno.mod | 8 +++++++- examples/gno.land/r/x/grc20_dynamic_call/baz/gno.mod | 8 +++++++- examples/gno.land/r/x/grc20_dynamic_call/foo/gno.mod | 8 +++++++- .../gno.land/r/x/grc20_dynamic_call/registry/gno.mod | 10 +++++++++- .../gno.land/r/x/grc20_dynamic_call/wrapper/gno.mod | 10 +++++++++- 5 files changed, 39 insertions(+), 5 deletions(-) diff --git a/examples/gno.land/r/x/grc20_dynamic_call/bar/gno.mod b/examples/gno.land/r/x/grc20_dynamic_call/bar/gno.mod index 25d8df533cb..97dc76d73b3 100644 --- a/examples/gno.land/r/x/grc20_dynamic_call/bar/gno.mod +++ b/examples/gno.land/r/x/grc20_dynamic_call/bar/gno.mod @@ -1 +1,7 @@ -module gno.land/r/x/grc20_dynamic_call/bar \ No newline at end of file +module gno.land/r/x/grc20_dynamic_call/bar + +require ( + gno.land/p/demo/grc/grc20 v0.0.0-latest + gno.land/p/demo/ufmt v0.0.0-latest + gno.land/r/demo/users v0.0.0-latest +) diff --git a/examples/gno.land/r/x/grc20_dynamic_call/baz/gno.mod b/examples/gno.land/r/x/grc20_dynamic_call/baz/gno.mod index 08cc2052e2c..3b0dc9b57bc 100644 --- a/examples/gno.land/r/x/grc20_dynamic_call/baz/gno.mod +++ b/examples/gno.land/r/x/grc20_dynamic_call/baz/gno.mod @@ -1 +1,7 @@ -module gno.land/r/x/grc20_dynamic_call/baz \ No newline at end of file +module gno.land/r/x/grc20_dynamic_call/baz + +require ( + gno.land/p/demo/grc/grc20 v0.0.0-latest + gno.land/p/demo/ufmt v0.0.0-latest + gno.land/r/demo/users v0.0.0-latest +) diff --git a/examples/gno.land/r/x/grc20_dynamic_call/foo/gno.mod b/examples/gno.land/r/x/grc20_dynamic_call/foo/gno.mod index c19f0909246..171f60edf53 100644 --- a/examples/gno.land/r/x/grc20_dynamic_call/foo/gno.mod +++ b/examples/gno.land/r/x/grc20_dynamic_call/foo/gno.mod @@ -1 +1,7 @@ -module gno.land/r/x/grc20_dynamic_call/foo \ No newline at end of file +module gno.land/r/x/grc20_dynamic_call/foo + +require ( + gno.land/p/demo/grc/grc20 v0.0.0-latest + gno.land/p/demo/ufmt v0.0.0-latest + gno.land/r/demo/users v0.0.0-latest +) diff --git a/examples/gno.land/r/x/grc20_dynamic_call/registry/gno.mod b/examples/gno.land/r/x/grc20_dynamic_call/registry/gno.mod index eae8c464276..394b4395063 100644 --- a/examples/gno.land/r/x/grc20_dynamic_call/registry/gno.mod +++ b/examples/gno.land/r/x/grc20_dynamic_call/registry/gno.mod @@ -1 +1,9 @@ -module gno.land/r/x/grc20_dynamic_call/registry \ No newline at end of file +module gno.land/r/x/grc20_dynamic_call/registry + +require ( + gno.land/r/demo/users v0.0.0-latest + gno.land/r/x/grc20_dynamic_call/bar v0.0.0-latest + gno.land/r/x/grc20_dynamic_call/baz v0.0.0-latest + gno.land/r/x/grc20_dynamic_call/foo v0.0.0-latest + gno.land/r/x/grc20_dynamic_call/wrapper v0.0.0-latest +) diff --git a/examples/gno.land/r/x/grc20_dynamic_call/wrapper/gno.mod b/examples/gno.land/r/x/grc20_dynamic_call/wrapper/gno.mod index a802235087a..3b0b1b01e37 100644 --- a/examples/gno.land/r/x/grc20_dynamic_call/wrapper/gno.mod +++ b/examples/gno.land/r/x/grc20_dynamic_call/wrapper/gno.mod @@ -1 +1,9 @@ -module gno.land/r/x/grc20_dynamic_call/wrapper \ No newline at end of file +module gno.land/r/x/grc20_dynamic_call/wrapper + +require ( + gno.land/r/demo/users v0.0.0-latest + gno.land/r/x/grc20_dynamic_call/bar v0.0.0-latest + gno.land/r/x/grc20_dynamic_call/baz v0.0.0-latest + gno.land/r/x/grc20_dynamic_call/foo v0.0.0-latest + gno.land/r/x/grc20_dynamic_call/registry v0.0.0-latest +) From 69a9a8f90b596f0b0c65b3486a676481ee7c81e5 Mon Sep 17 00:00:00 2001 From: n3wbie Date: Thu, 7 Dec 2023 14:35:49 +0900 Subject: [PATCH 4/8] fix: adresss type and value --- .../grc20_dynamic_call/registry/registry.gno | 6 ++--- .../registry/registry_test.gno | 23 ++++++++++++------- 2 files changed, 18 insertions(+), 11 deletions(-) diff --git a/examples/gno.land/r/x/grc20_dynamic_call/registry/registry.gno b/examples/gno.land/r/x/grc20_dynamic_call/registry/registry.gno index ebf0dc72215..21be84253df 100644 --- a/examples/gno.land/r/x/grc20_dynamic_call/registry/registry.gno +++ b/examples/gno.land/r/x/grc20_dynamic_call/registry/registry.gno @@ -68,7 +68,7 @@ func UnregisterGRC20Interface(pkgPath string) { } } -func TransferByInterfaceName(pkgPath string, to string, amount uint64) bool { +func TransferByInterfaceName(pkgPath string, to std.Address, amount uint64) bool { i, found := findGRC20(pkgPath) if !found { return false @@ -79,7 +79,7 @@ func TransferByInterfaceName(pkgPath string, to string, amount uint64) bool { return true } -func TransferFromByInterfaceName(pkgPath string, from, to string, amount uint64) bool { +func TransferFromByInterfaceName(pkgPath string, from, to std.Address, amount uint64) bool { i, found := findGRC20(pkgPath) if !found { return false @@ -90,7 +90,7 @@ func TransferFromByInterfaceName(pkgPath string, from, to string, amount uint64) return true } -func BalanceOfByInterfaceName(pkgPath string, owner string) uint64 { +func BalanceOfByInterfaceName(pkgPath string, owner std.Address) uint64 { i, found := findGRC20(pkgPath) if !found { return 0 diff --git a/examples/gno.land/r/x/grc20_dynamic_call/registry/registry_test.gno b/examples/gno.land/r/x/grc20_dynamic_call/registry/registry_test.gno index a3b0fb5c963..d835723095d 100644 --- a/examples/gno.land/r/x/grc20_dynamic_call/registry/registry_test.gno +++ b/examples/gno.land/r/x/grc20_dynamic_call/registry/registry_test.gno @@ -8,23 +8,30 @@ import ( "gno.land/r/x/grc20_dynamic_call/baz" "gno.land/r/x/grc20_dynamic_call/foo" - "gno.land/r/demo/users" - _ "gno.land/r/x/grc20_dynamic_call/wrapper" -) -const ( - transferTo string = "g12345" + "gno.land/p/demo/testutils" - transferFromFrom string = "g12345" - transferFromTo string = "g54321" + "gno.land/r/demo/users" ) -var cRealmAddr std.Address +var ( + cRealmAddr std.Address + + transferTo std.Address + + transferFromFrom std.Address + transferFromTo std.Address +) func init() { cRealmAddr = std.CurrentRealm().Addr() + transferTo = testutils.TestAddress("transferTo") + + transferFromFrom = transferTo // use transferTo as transferFromFrom + transferFromTo = testutils.TestAddress("transferFromTo") + std.TestSetOrigCaller(cRealmAddr) foo.Faucet() bar.Faucet() From 7e9a62fed8e58b3e2ab1189a557c4d3d56f2e0bc Mon Sep 17 00:00:00 2001 From: n3wbie Date: Tue, 13 Feb 2024 17:05:46 +0900 Subject: [PATCH 5/8] chore: remove old --- .../r/x/grc20_dynamic_call/baz/baz.gno | 130 -------------- .../r/x/grc20_dynamic_call/baz/gno.mod | 7 - .../registry/registry_test.gno | 170 ------------------ .../r/x/grc20_dynamic_call/wrapper/gno.mod | 9 - .../x/grc20_dynamic_call/wrapper/wrapper.gno | 65 ------- 5 files changed, 381 deletions(-) delete mode 100644 examples/gno.land/r/x/grc20_dynamic_call/baz/baz.gno delete mode 100644 examples/gno.land/r/x/grc20_dynamic_call/baz/gno.mod delete mode 100644 examples/gno.land/r/x/grc20_dynamic_call/registry/registry_test.gno delete mode 100644 examples/gno.land/r/x/grc20_dynamic_call/wrapper/gno.mod delete mode 100644 examples/gno.land/r/x/grc20_dynamic_call/wrapper/wrapper.gno diff --git a/examples/gno.land/r/x/grc20_dynamic_call/baz/baz.gno b/examples/gno.land/r/x/grc20_dynamic_call/baz/baz.gno deleted file mode 100644 index f0393edac52..00000000000 --- a/examples/gno.land/r/x/grc20_dynamic_call/baz/baz.gno +++ /dev/null @@ -1,130 +0,0 @@ -package baz - -import ( - "std" - "strings" - - "gno.land/p/demo/grc/grc20" - "gno.land/p/demo/ufmt" - "gno.land/r/demo/users" -) - -var ( - baz *grc20.AdminToken - admin std.Address = "g1us8428u2a5satrlxzagqqa5m6vmuze025anjlj" // TODO: helper to change admin -) - -func init() { - baz = grc20.NewAdminToken("Baz", "BAZ", 4) - baz.Mint(admin, 1000000*10000) // @administrator (1M) - baz.Mint("g1u7y667z64x2h7vc6fmpcprgey4ck233jaww9zq", 10000*10000) // @manfred (10k) -} - -// method proxies as public functions. -// - -// getters. - -func TotalSupply() uint64 { - return baz.TotalSupply() -} - -func BalanceOf(owner users.AddressOrName) uint64 { - balance, err := baz.BalanceOf(owner.Resolve()) - if err != nil { - panic(err) - } - return balance -} - -func Allowance(owner, spender users.AddressOrName) uint64 { - allowance, err := baz.Allowance(owner.Resolve(), spender.Resolve()) - if err != nil { - panic(err) - } - return allowance -} - -// setters. - -func Transfer(to users.AddressOrName, amount uint64) { - caller := std.PrevRealm().Addr() - err := baz.Transfer(caller, to.Resolve(), amount) - if err != nil { - panic(err) - } -} - -func Approve(spender users.AddressOrName, amount uint64) { - // caller := std.PrevRealm().Addr() - caller := std.GetOrigCaller() - err := baz.Approve(caller, spender.Resolve(), amount) - if err != nil { - panic(err) - } -} - -func TransferFrom(from, to users.AddressOrName, amount uint64) { - caller := std.PrevRealm().Addr() - err := baz.TransferFrom(caller, from.Resolve(), to.Resolve(), amount) - if err != nil { - panic(err) - } -} - -// faucet. - -func Faucet() { - // FIXME: add limits? - // FIXME: add payment in gnot? - caller := std.PrevRealm().Addr() - err := baz.Mint(caller, 1000*10000) // 1k - if err != nil { - panic(err) - } -} - -// administration. - -func Mint(address users.AddressOrName, amount uint64) { - caller := std.PrevRealm().Addr() - assertIsAdmin(caller) - err := baz.Mint(address.Resolve(), amount) - if err != nil { - panic(err) - } -} - -func Burn(address users.AddressOrName, amount uint64) { - caller := std.PrevRealm().Addr() - assertIsAdmin(caller) - err := baz.Burn(address.Resolve(), amount) - if err != nil { - panic(err) - } -} - -// render. -// - -func Render(path string) string { - parts := strings.Split(path, "/") - c := len(parts) - - switch { - case path == "": - return baz.RenderHome() - case c == 2 && parts[0] == "balance": - owner := users.AddressOrName(parts[1]) - balance, _ := baz.BalanceOf(owner.Resolve()) - return ufmt.Sprintf("%d\n", balance) - default: - return "404\n" - } -} - -func assertIsAdmin(address std.Address) { - if address != admin { - panic("restricted access") - } -} diff --git a/examples/gno.land/r/x/grc20_dynamic_call/baz/gno.mod b/examples/gno.land/r/x/grc20_dynamic_call/baz/gno.mod deleted file mode 100644 index 3b0dc9b57bc..00000000000 --- a/examples/gno.land/r/x/grc20_dynamic_call/baz/gno.mod +++ /dev/null @@ -1,7 +0,0 @@ -module gno.land/r/x/grc20_dynamic_call/baz - -require ( - gno.land/p/demo/grc/grc20 v0.0.0-latest - gno.land/p/demo/ufmt v0.0.0-latest - gno.land/r/demo/users v0.0.0-latest -) diff --git a/examples/gno.land/r/x/grc20_dynamic_call/registry/registry_test.gno b/examples/gno.land/r/x/grc20_dynamic_call/registry/registry_test.gno deleted file mode 100644 index d835723095d..00000000000 --- a/examples/gno.land/r/x/grc20_dynamic_call/registry/registry_test.gno +++ /dev/null @@ -1,170 +0,0 @@ -package registry - -import ( - "std" - "testing" - - "gno.land/r/x/grc20_dynamic_call/bar" - "gno.land/r/x/grc20_dynamic_call/baz" - "gno.land/r/x/grc20_dynamic_call/foo" - - _ "gno.land/r/x/grc20_dynamic_call/wrapper" - - "gno.land/p/demo/testutils" - - "gno.land/r/demo/users" -) - -var ( - cRealmAddr std.Address - - transferTo std.Address - - transferFromFrom std.Address - transferFromTo std.Address -) - -func init() { - cRealmAddr = std.CurrentRealm().Addr() - - transferTo = testutils.TestAddress("transferTo") - - transferFromFrom = transferTo // use transferTo as transferFromFrom - transferFromTo = testutils.TestAddress("transferFromTo") - - std.TestSetOrigCaller(cRealmAddr) - foo.Faucet() - bar.Faucet() - baz.Faucet() -} - -func TestTransferByNameFOO(t *testing.T) { - fooBalance := BalanceOfByInterfaceName("gno.land/r/x/grc20_dynamic_call/foo", transferTo) - if fooBalance != 0 { - t.Fatal("transferTo should have 0 FOO but", fooBalance) - } - - TransferByInterfaceName("gno.land/r/x/grc20_dynamic_call/foo", transferTo, 12345) - - fooBalance = BalanceOfByInterfaceName("gno.land/r/x/grc20_dynamic_call/foo", transferTo) - if fooBalance != 12345 { - t.Fatal("transferTo should have 12345 FOO, but", fooBalance) - } -} - -func TestTransferByNameBAR(t *testing.T) { - barBalance := BalanceOfByInterfaceName("gno.land/r/x/grc20_dynamic_call/bar", transferTo) - if barBalance != 0 { - t.Fatal("transferTo should have 0 BAR but", barBalance) - } - - TransferByInterfaceName("gno.land/r/x/grc20_dynamic_call/bar", transferTo, 12345) - - barBalance = BalanceOfByInterfaceName("gno.land/r/x/grc20_dynamic_call/bar", transferTo) - if barBalance != 12345 { - t.Fatal("transferTo should have 12345 BAR, but", barBalance) - } -} - -func TestTransferByNameBAZ(t *testing.T) { - bazBalance := BalanceOfByInterfaceName("gno.land/r/x/grc20_dynamic_call/baz", transferTo) - if bazBalance != 0 { - t.Fatal("transferTo should have 0 BAZ but", bazBalance) - } - - TransferByInterfaceName("gno.land/r/x/grc20_dynamic_call/baz", transferTo, 12345) - - bazBalance = BalanceOfByInterfaceName("gno.land/r/x/grc20_dynamic_call/baz", transferTo) - if bazBalance != 12345 { - t.Fatal("transferTo should have 12345 BAZ, but", bazBalance) - } -} - -func TestTransferFromByNameFOO(t *testing.T) { - fooBalanceTo := BalanceOfByInterfaceName("gno.land/r/x/grc20_dynamic_call/foo", transferFromTo) - if fooBalanceTo != 0 { - t.Fatal("transferFromTo should have 0 FOO, but", fooBalanceTo) - } - - std.TestSetOrigCaller(transferFromFrom) - foo.Approve(users.AddressOrName(cRealmAddr), 5) - TransferFromByInterfaceName("gno.land/r/x/grc20_dynamic_call/foo", transferFromFrom, transferFromTo, 3) - - fooBalanceTo = BalanceOfByInterfaceName("gno.land/r/x/grc20_dynamic_call/foo", transferFromTo) - if fooBalanceTo != 3 { - t.Fatal("transferFromTo should have 3 FOO, but", fooBalanceTo) - } - - fooBalanceFrom := BalanceOfByInterfaceName("gno.land/r/x/grc20_dynamic_call/foo", transferFromFrom) - if fooBalanceFrom != 12342 { - t.Fatal("transferFromFrom should have 12342 FOO, but", fooBalanceFrom) - } -} - -func TestTransferFromByNameBAR(t *testing.T) { - barBalanceTo := BalanceOfByInterfaceName("gno.land/r/x/grc20_dynamic_call/bar", transferFromTo) - if barBalanceTo != 0 { - t.Fatal("transferFromTo should have 0 BAR, but", barBalanceTo) - } - - std.TestSetOrigCaller(transferFromFrom) - bar.Approve(users.AddressOrName(cRealmAddr), 5) - TransferFromByInterfaceName("gno.land/r/x/grc20_dynamic_call/bar", transferFromFrom, transferFromTo, 3) - - barBalanceTo = BalanceOfByInterfaceName("gno.land/r/x/grc20_dynamic_call/bar", transferFromTo) - if barBalanceTo != 3 { - t.Fatal("transferFromTo should have 3 BAR, but", barBalanceTo) - } - - barBalanceFrom := BalanceOfByInterfaceName("gno.land/r/x/grc20_dynamic_call/bar", transferFromFrom) - if barBalanceFrom != 12342 { - t.Fatal("transferFromFrom should have 12342 BAR, but", barBalanceFrom) - } -} - -func TestTransferFromByNameBAZ(t *testing.T) { - bazBalanceTo := BalanceOfByInterfaceName("gno.land/r/x/grc20_dynamic_call/baz", transferFromTo) - if bazBalanceTo != 0 { - t.Fatal("transferFromTo should have 0 BAZ, but", bazBalanceTo) - } - - std.TestSetOrigCaller(transferFromFrom) - baz.Approve(users.AddressOrName(cRealmAddr), 5) - TransferFromByInterfaceName("gno.land/r/x/grc20_dynamic_call/baz", transferFromFrom, transferFromTo, 3) - - bazBalanceTo = BalanceOfByInterfaceName("gno.land/r/x/grc20_dynamic_call/baz", transferFromTo) - if bazBalanceTo != 3 { - t.Fatal("transferFromTo should have 3 BAZ, but", bazBalanceTo) - } - - bazBalanceFrom := BalanceOfByInterfaceName("gno.land/r/x/grc20_dynamic_call/baz", transferFromFrom) - if bazBalanceFrom != 12342 { - t.Fatal("transferFromFrom should have 12342 BAZ, but", bazBalanceFrom) - } -} - -func TestUnregisterUnauthorized(t *testing.T) { - shouldPanic(t, func() { UnregisterGRC20Interface("gno.land/r/x/grc20_dynamic_call/foo") }) -} - -func TestUnregisterAuthorized(t *testing.T) { - if len(registered) != 3 { - t.Fatal("should have 3 registered interfaces but", len(registered)) - } - - std.TestSetOrigCaller("g1sqt92sa06ugh8nlt98kyghw83qy84paf4csyh6") - UnregisterGRC20Interface("gno.land/r/x/grc20_dynamic_call/foo") - - if len(registered) != 2 { - t.Fatal("should have 2 registered interfaces") - } -} - -func shouldPanic(t *testing.T, f func()) { - defer func() { - if r := recover(); r == nil { - t.Errorf("expected panic") - } - }() - f() -} diff --git a/examples/gno.land/r/x/grc20_dynamic_call/wrapper/gno.mod b/examples/gno.land/r/x/grc20_dynamic_call/wrapper/gno.mod deleted file mode 100644 index 3b0b1b01e37..00000000000 --- a/examples/gno.land/r/x/grc20_dynamic_call/wrapper/gno.mod +++ /dev/null @@ -1,9 +0,0 @@ -module gno.land/r/x/grc20_dynamic_call/wrapper - -require ( - gno.land/r/demo/users v0.0.0-latest - gno.land/r/x/grc20_dynamic_call/bar v0.0.0-latest - gno.land/r/x/grc20_dynamic_call/baz v0.0.0-latest - gno.land/r/x/grc20_dynamic_call/foo v0.0.0-latest - gno.land/r/x/grc20_dynamic_call/registry v0.0.0-latest -) diff --git a/examples/gno.land/r/x/grc20_dynamic_call/wrapper/wrapper.gno b/examples/gno.land/r/x/grc20_dynamic_call/wrapper/wrapper.gno deleted file mode 100644 index 6c81c9a6d2e..00000000000 --- a/examples/gno.land/r/x/grc20_dynamic_call/wrapper/wrapper.gno +++ /dev/null @@ -1,65 +0,0 @@ -package wrapper - -import ( - "gno.land/r/demo/users" - - "gno.land/r/x/grc20_dynamic_call/bar" - "gno.land/r/x/grc20_dynamic_call/baz" - "gno.land/r/x/grc20_dynamic_call/foo" - - "gno.land/r/x/grc20_dynamic_call/registry" -) - -type FooTokenInterface struct{} - -func (FooTokenInterface) Transfer() func(to users.AddressOrName, amount uint64) { - return foo.Transfer -} - -func (FooTokenInterface) TransferFrom() func(from, to users.AddressOrName, amount uint64) { - return foo.TransferFrom -} - -func (FooTokenInterface) BalanceOf() func(owner users.AddressOrName) uint64 { - return foo.BalanceOf -} - -var _ registry.GRC20Interface = FooTokenInterface{} - -type BarTokenInterface struct{} - -func (BarTokenInterface) Transfer() func(to users.AddressOrName, amount uint64) { - return bar.Transfer -} - -func (BarTokenInterface) TransferFrom() func(from, to users.AddressOrName, amount uint64) { - return bar.TransferFrom -} - -func (BarTokenInterface) BalanceOf() func(owner users.AddressOrName) uint64 { - return bar.BalanceOf -} - -var _ registry.GRC20Interface = BarTokenInterface{} - -type BazTokenInterface struct{} - -func (BazTokenInterface) Transfer() func(to users.AddressOrName, amount uint64) { - return baz.Transfer -} - -func (BazTokenInterface) TransferFrom() func(from, to users.AddressOrName, amount uint64) { - return baz.TransferFrom -} - -func (BazTokenInterface) BalanceOf() func(owner users.AddressOrName) uint64 { - return baz.BalanceOf -} - -var _ registry.GRC20Interface = BazTokenInterface{} - -func init() { - registry.RegisterGRC20Interface("gno.land/r/x/grc20_dynamic_call/foo", FooTokenInterface{}) - registry.RegisterGRC20Interface("gno.land/r/x/grc20_dynamic_call/bar", BarTokenInterface{}) - registry.RegisterGRC20Interface("gno.land/r/x/grc20_dynamic_call/baz", BazTokenInterface{}) -} From 86c267f68b524d5ef00c7afc588d25988da6c5c3 Mon Sep 17 00:00:00 2001 From: n3wbie Date: Tue, 13 Feb 2024 17:07:19 +0900 Subject: [PATCH 6/8] feat: use map instead of []struct --- .../grc20_dynamic_call/registry/registry.gno | 77 +++++++------------ 1 file changed, 28 insertions(+), 49 deletions(-) diff --git a/examples/gno.land/r/x/grc20_dynamic_call/registry/registry.gno b/examples/gno.land/r/x/grc20_dynamic_call/registry/registry.gno index 21be84253df..ddb1d6f567f 100644 --- a/examples/gno.land/r/x/grc20_dynamic_call/registry/registry.gno +++ b/examples/gno.land/r/x/grc20_dynamic_call/registry/registry.gno @@ -3,12 +3,14 @@ package registry import ( "std" + "gno.land/p/demo/ufmt" + "gno.land/r/demo/users" ) -const APPROVED_UNREGISTER_CALLER = "g1sqt92sa06ugh8nlt98kyghw83qy84paf4csyh6" - -var registered = []GRC20Pair{} +const ( + APPROVED_UNREGISTER_CALLER = "g1sqt92sa06ugh8nlt98kyghw83qy84paf4csyh6" // like admin +) type GRC20Interface interface { Transfer() func(to users.AddressOrName, amount uint64) @@ -16,86 +18,63 @@ type GRC20Interface interface { BalanceOf() func(owner users.AddressOrName) uint64 } -type GRC20Pair struct { - pkgPath string - igrc20 GRC20Interface -} - -func findGRC20(pkgPath string) (int, bool) { - for i, pair := range registered { - if pair.pkgPath == pkgPath { - return i, true - } - } - - return -1, false -} - -func appendGRC20Interface(pkgPath string, igrc20 GRC20Interface) { - registered = append(registered, GRC20Pair{pkgPath: pkgPath, igrc20: igrc20}) -} - -func removeGRC20Interface(pkgPath string) { - i, found := findGRC20(pkgPath) - if !found { - return - } - - registered = append(registered[:i], registered[i+1:]...) -} +var ( + registered = make(map[string]GRC20Interface) +) func RegisterGRC20Interface(pkgPath string, igrc20 GRC20Interface) { - _, found := findGRC20(pkgPath) + _, found := registered[pkgPath] if found { - panic("GRC20 already registered") + panic(ufmt.Sprintf("GRC20(pkgPath:%s) already registered", pkgPath)) } - appendGRC20Interface(pkgPath, igrc20) + registered[pkgPath] = igrc20 } func UnregisterGRC20Interface(pkgPath string) { // do not allow realm to unregister std.AssertOriginCall() - caller := std.GetOrigCaller() + caller := std.GetOrigCaller() if caller != APPROVED_UNREGISTER_CALLER { panic("unauthorized") } - _, found := findGRC20(pkgPath) + _, found := registered[pkgPath] if found { - removeGRC20Interface(pkgPath) + delete(registered, pkgPath) } } -func TransferByInterfaceName(pkgPath string, to std.Address, amount uint64) bool { - i, found := findGRC20(pkgPath) +func BalanceOfByInterface(pkgPath string, owner std.Address) uint64 { + igrc20, found := registered[pkgPath] if !found { return false } - registered[i].igrc20.Transfer()(users.AddressOrName(to), amount) - - return true + return igrc20.BalanceOf()(users.AddressOrName(owner)) } -func TransferFromByInterfaceName(pkgPath string, from, to std.Address, amount uint64) bool { - i, found := findGRC20(pkgPath) +func TransferByInterface(pkgPath string, to std.Address, amount uint64) bool { + igrc20, found := registered[pkgPath] if !found { return false } - registered[i].igrc20.TransferFrom()(users.AddressOrName(from), users.AddressOrName(to), amount) + // will panic if transfer fails + igrc20.Transfer()(users.AddressOrName(to), amount) return true } -func BalanceOfByInterfaceName(pkgPath string, owner std.Address) uint64 { - i, found := findGRC20(pkgPath) +func TransferFromByInterface(pkgPath string, from, to std.Address, amount uint64) bool { + igrc20, found := registered[pkgPath] if !found { - return 0 + return false } - balance := registered[i].igrc20.BalanceOf()(users.AddressOrName(owner)) - return balance + // will panic if transferFrom fails + igrc20.TransferFrom()(users.AddressOrName(from), users.AddressOrName(to), amount) + + return true } From fdbf927901c002b4d438636f763d70fcdf2ac3bf Mon Sep 17 00:00:00 2001 From: n3wbie Date: Tue, 13 Feb 2024 17:09:32 +0900 Subject: [PATCH 7/8] fix: testcase --- .../r/x/grc20_dynamic_call/bar/bar.gno | 21 ++--- .../r/x/grc20_dynamic_call/foo/foo.gno | 21 ++--- .../r/x/grc20_dynamic_call/registry/gno.mod | 5 +- .../registry/z_0_transfer_filetest.gno | 87 +++++++++++++++++++ .../registry/z_1_transferfrom_filetest.gno | 79 +++++++++++++++++ 5 files changed, 189 insertions(+), 24 deletions(-) create mode 100644 examples/gno.land/r/x/grc20_dynamic_call/registry/z_0_transfer_filetest.gno create mode 100644 examples/gno.land/r/x/grc20_dynamic_call/registry/z_1_transferfrom_filetest.gno diff --git a/examples/gno.land/r/x/grc20_dynamic_call/bar/bar.gno b/examples/gno.land/r/x/grc20_dynamic_call/bar/bar.gno index 1638971f63d..21abd647dbc 100644 --- a/examples/gno.land/r/x/grc20_dynamic_call/bar/bar.gno +++ b/examples/gno.land/r/x/grc20_dynamic_call/bar/bar.gno @@ -18,6 +18,8 @@ func init() { bar = grc20.NewAdminToken("Bar", "BAR", 4) bar.Mint(admin, 1000000*10000) // @administrator (1M) bar.Mint("g1u7y667z64x2h7vc6fmpcprgey4ck233jaww9zq", 10000*10000) // @manfred (10k) + + bar.Mint("g1tkmrcu9m0xjddxh0c29r3zac8m2yjwaytlvh6u", 1000*10000) // REALM_gno.land/r/x/grc20_dynamic_call/registry } // method proxies as public functions. @@ -32,7 +34,7 @@ func TotalSupply() uint64 { func BalanceOf(owner users.AddressOrName) uint64 { balance, err := bar.BalanceOf(owner.Resolve()) if err != nil { - panic(err) + panic(err.Error()) } return balance } @@ -40,7 +42,7 @@ func BalanceOf(owner users.AddressOrName) uint64 { func Allowance(owner, spender users.AddressOrName) uint64 { allowance, err := bar.Allowance(owner.Resolve(), spender.Resolve()) if err != nil { - panic(err) + panic(err.Error()) } return allowance } @@ -51,16 +53,15 @@ func Transfer(to users.AddressOrName, amount uint64) { caller := std.PrevRealm().Addr() err := bar.Transfer(caller, to.Resolve(), amount) if err != nil { - panic(err) + panic(err.Error()) } } func Approve(spender users.AddressOrName, amount uint64) { - // caller := std.PrevRealm().Addr() - caller := std.GetOrigCaller() + caller := std.PrevRealm().Addr() err := bar.Approve(caller, spender.Resolve(), amount) if err != nil { - panic(err) + panic(err.Error()) } } @@ -68,7 +69,7 @@ func TransferFrom(from, to users.AddressOrName, amount uint64) { caller := std.PrevRealm().Addr() err := bar.TransferFrom(caller, from.Resolve(), to.Resolve(), amount) if err != nil { - panic(err) + panic(err.Error()) } } @@ -80,7 +81,7 @@ func Faucet() { caller := std.PrevRealm().Addr() err := bar.Mint(caller, 1000*10000) // 1k if err != nil { - panic(err) + panic(err.Error()) } } @@ -91,7 +92,7 @@ func Mint(address users.AddressOrName, amount uint64) { assertIsAdmin(caller) err := bar.Mint(address.Resolve(), amount) if err != nil { - panic(err) + panic(err.Error()) } } @@ -100,7 +101,7 @@ func Burn(address users.AddressOrName, amount uint64) { assertIsAdmin(caller) err := bar.Burn(address.Resolve(), amount) if err != nil { - panic(err) + panic(err.Error()) } } diff --git a/examples/gno.land/r/x/grc20_dynamic_call/foo/foo.gno b/examples/gno.land/r/x/grc20_dynamic_call/foo/foo.gno index 7377bdc744c..d3e8d5c5e4b 100644 --- a/examples/gno.land/r/x/grc20_dynamic_call/foo/foo.gno +++ b/examples/gno.land/r/x/grc20_dynamic_call/foo/foo.gno @@ -18,6 +18,8 @@ func init() { foo = grc20.NewAdminToken("Foo", "FOO", 4) foo.Mint(admin, 1000000*10000) // @administrator (1M) foo.Mint("g1u7y667z64x2h7vc6fmpcprgey4ck233jaww9zq", 10000*10000) // @manfred (10k) + + foo.Mint("g1tkmrcu9m0xjddxh0c29r3zac8m2yjwaytlvh6u", 1000*10000) // REALM_gno.land/r/x/grc20_dynamic_call/registry } // method proxies as public functions. @@ -32,7 +34,7 @@ func TotalSupply() uint64 { func BalanceOf(owner users.AddressOrName) uint64 { balance, err := foo.BalanceOf(owner.Resolve()) if err != nil { - panic(err) + panic(err.Error()) } return balance } @@ -40,7 +42,7 @@ func BalanceOf(owner users.AddressOrName) uint64 { func Allowance(owner, spender users.AddressOrName) uint64 { allowance, err := foo.Allowance(owner.Resolve(), spender.Resolve()) if err != nil { - panic(err) + panic(err.Error()) } return allowance } @@ -51,16 +53,15 @@ func Transfer(to users.AddressOrName, amount uint64) { caller := std.PrevRealm().Addr() err := foo.Transfer(caller, to.Resolve(), amount) if err != nil { - panic(err) + panic(err.Error()) } } func Approve(spender users.AddressOrName, amount uint64) { - // caller := std.PrevRealm().Addr() - caller := std.GetOrigCaller() + caller := std.PrevRealm().Addr() err := foo.Approve(caller, spender.Resolve(), amount) if err != nil { - panic(err) + panic(err.Error()) } } @@ -68,7 +69,7 @@ func TransferFrom(from, to users.AddressOrName, amount uint64) { caller := std.PrevRealm().Addr() err := foo.TransferFrom(caller, from.Resolve(), to.Resolve(), amount) if err != nil { - panic(err) + panic(err.Error()) } } @@ -80,7 +81,7 @@ func Faucet() { caller := std.PrevRealm().Addr() err := foo.Mint(caller, 1000*10000) // 1k if err != nil { - panic(err) + panic(err.Error()) } } @@ -91,7 +92,7 @@ func Mint(address users.AddressOrName, amount uint64) { assertIsAdmin(caller) err := foo.Mint(address.Resolve(), amount) if err != nil { - panic(err) + panic(err.Error()) } } @@ -100,7 +101,7 @@ func Burn(address users.AddressOrName, amount uint64) { assertIsAdmin(caller) err := foo.Burn(address.Resolve(), amount) if err != nil { - panic(err) + panic(err.Error()) } } diff --git a/examples/gno.land/r/x/grc20_dynamic_call/registry/gno.mod b/examples/gno.land/r/x/grc20_dynamic_call/registry/gno.mod index 394b4395063..c1c83c949c5 100644 --- a/examples/gno.land/r/x/grc20_dynamic_call/registry/gno.mod +++ b/examples/gno.land/r/x/grc20_dynamic_call/registry/gno.mod @@ -1,9 +1,6 @@ module gno.land/r/x/grc20_dynamic_call/registry require ( + gno.land/p/demo/ufmt v0.0.0-latest gno.land/r/demo/users v0.0.0-latest - gno.land/r/x/grc20_dynamic_call/bar v0.0.0-latest - gno.land/r/x/grc20_dynamic_call/baz v0.0.0-latest - gno.land/r/x/grc20_dynamic_call/foo v0.0.0-latest - gno.land/r/x/grc20_dynamic_call/wrapper v0.0.0-latest ) diff --git a/examples/gno.land/r/x/grc20_dynamic_call/registry/z_0_transfer_filetest.gno b/examples/gno.land/r/x/grc20_dynamic_call/registry/z_0_transfer_filetest.gno new file mode 100644 index 00000000000..6d7a7016a3f --- /dev/null +++ b/examples/gno.land/r/x/grc20_dynamic_call/registry/z_0_transfer_filetest.gno @@ -0,0 +1,87 @@ +// PKGPATH: gno.land/r/x/grc20_dynamic_call/registries_test +package registries_test + +import ( + "std" + + "gno.land/p/demo/testutils" + + "gno.land/r/x/grc20_dynamic_call/registry" + + "gno.land/r/x/grc20_dynamic_call/bar" + "gno.land/r/x/grc20_dynamic_call/foo" + + "gno.land/r/demo/users" +) + +var ( + actualRealmAddr std.Address + transferTo std.Address +) + +// FOO +type FooStruct struct{} + +func (FooStruct) Transfer() func(to users.AddressOrName, amount uint64) { + return foo.Transfer +} +func (FooStruct) TransferFrom() func(from, to users.AddressOrName, amount uint64) { + return foo.TransferFrom +} +func (FooStruct) BalanceOf() func(owner users.AddressOrName) uint64 { + return foo.BalanceOf +} + +// BAR +type BarStruct struct{} + +func (BarStruct) Transfer() func(to users.AddressOrName, amount uint64) { + return bar.Transfer +} +func (BarStruct) TransferFrom() func(from, to users.AddressOrName, amount uint64) { + return bar.TransferFrom +} +func (BarStruct) BalanceOf() func(owner users.AddressOrName) uint64 { + return bar.BalanceOf +} + +func init() { + registry.RegisterGRC20Interface("gno.land/r/x/grc20_dynamic_call/foo", FooStruct{}) + registry.RegisterGRC20Interface("gno.land/r/x/grc20_dynamic_call/bar", BarStruct{}) + + actualRealmAddr = std.DerivePkgAddr("gno.land/r/x/grc20_dynamic_call/registry") + + transferTo = testutils.TestAddress("transferTo") +} + +func main() { + // FOO + fooBalanceRealm := registry.BalanceOfByInterface("gno.land/r/x/grc20_dynamic_call/foo", actualRealmAddr) + println(fooBalanceRealm) + + fooBalanceTo := registry.BalanceOfByInterface("gno.land/r/x/grc20_dynamic_call/foo", transferTo) + println(fooBalanceTo) + + registry.TransferByInterface("gno.land/r/x/grc20_dynamic_call/foo", transferTo, 12345) + fooBalanceTo = registry.BalanceOfByInterface("gno.land/r/x/grc20_dynamic_call/foo", transferTo) + println(fooBalanceTo) + + // BAR + barBalanceRealm := registry.BalanceOfByInterface("gno.land/r/x/grc20_dynamic_call/bar", actualRealmAddr) + println(barBalanceRealm) + + barBalanceTo := registry.BalanceOfByInterface("gno.land/r/x/grc20_dynamic_call/bar", transferTo) + println(barBalanceTo) + + registry.TransferByInterface("gno.land/r/x/grc20_dynamic_call/bar", transferTo, 54321) + barBalanceTo = registry.BalanceOfByInterface("gno.land/r/x/grc20_dynamic_call/bar", transferTo) + println(barBalanceTo) +} + +// Output: +// 10000000 +// 0 +// 12345 +// 10000000 +// 0 +// 54321 diff --git a/examples/gno.land/r/x/grc20_dynamic_call/registry/z_1_transferfrom_filetest.gno b/examples/gno.land/r/x/grc20_dynamic_call/registry/z_1_transferfrom_filetest.gno new file mode 100644 index 00000000000..a5f87ccf399 --- /dev/null +++ b/examples/gno.land/r/x/grc20_dynamic_call/registry/z_1_transferfrom_filetest.gno @@ -0,0 +1,79 @@ +package main + +import ( + "std" + + "gno.land/p/demo/testutils" + + "gno.land/r/x/grc20_dynamic_call/registry" + + "gno.land/r/x/grc20_dynamic_call/bar" + "gno.land/r/x/grc20_dynamic_call/foo" + + "gno.land/r/demo/users" +) + +var ( + actualRealmAddr std.Address + + transferFromFrom std.Address = testutils.TestAddress("transferFromFrom") + transferFromTo std.Address = testutils.TestAddress("transferFromTo") +) + +// FOO +type FooStruct struct{} + +func (FooStruct) Transfer() func(to users.AddressOrName, amount uint64) { + return foo.Transfer +} +func (FooStruct) TransferFrom() func(from, to users.AddressOrName, amount uint64) { + return foo.TransferFrom +} +func (FooStruct) BalanceOf() func(owner users.AddressOrName) uint64 { + return foo.BalanceOf +} + +// BAR +type BarStruct struct{} + +func (BarStruct) Transfer() func(to users.AddressOrName, amount uint64) { + return bar.Transfer +} +func (BarStruct) TransferFrom() func(from, to users.AddressOrName, amount uint64) { + return bar.TransferFrom +} +func (BarStruct) BalanceOf() func(owner users.AddressOrName) uint64 { + return bar.BalanceOf +} + +func init() { + registry.RegisterGRC20Interface("gno.land/r/x/grc20_dynamic_call/foo", FooStruct{}) + registry.RegisterGRC20Interface("gno.land/r/x/grc20_dynamic_call/bar", BarStruct{}) + + actualRealmAddr = std.DerivePkgAddr("gno.land/r/x/grc20_dynamic_call/registry") +} + +func main() { + foo.Faucet() + foo.Approve(users.AddressOrName(std.DerivePkgAddr("gno.land/r/x/grc20_dynamic_call/registry")), 1000*10000) + + fooBalanceOrigCaller := registry.BalanceOfByInterface("gno.land/r/x/grc20_dynamic_call/foo", std.GetOrigCaller()) + println(fooBalanceOrigCaller) + + fooBalanceTo := registry.BalanceOfByInterface("gno.land/r/x/grc20_dynamic_call/foo", transferFromTo) + println(fooBalanceTo) + + registry.TransferFromByInterface("gno.land/r/x/grc20_dynamic_call/foo", std.GetOrigCaller(), transferFromTo, 54321) + + fooBalanceOrigCaller = registry.BalanceOfByInterface("gno.land/r/x/grc20_dynamic_call/foo", std.GetOrigCaller()) + println(fooBalanceOrigCaller) + + fooBalanceTo = registry.BalanceOfByInterface("gno.land/r/x/grc20_dynamic_call/foo", transferFromTo) + println(fooBalanceTo) +} + +// Output: +// 10000000 +// 0 +// 9945679 +// 54321 From 36ef3bbdf9a9997ff5388d70f306936fee61fd56 Mon Sep 17 00:00:00 2001 From: n3wbie Date: Tue, 13 Feb 2024 17:09:40 +0900 Subject: [PATCH 8/8] fix: map copy --- gnovm/pkg/gnolang/realm.go | 2 ++ 1 file changed, 2 insertions(+) diff --git a/gnovm/pkg/gnolang/realm.go b/gnovm/pkg/gnolang/realm.go index 519b183ad3a..a6c5d3d6cdb 100644 --- a/gnovm/pkg/gnolang/realm.go +++ b/gnovm/pkg/gnolang/realm.go @@ -1356,6 +1356,8 @@ func fillTypesOfValue(store Store, val Value) Value { for cur := cv.List.Head; cur != nil; cur = cur.Next { fillTypesTV(store, &cur.Key) fillTypesTV(store, &cur.Value) + + cv.vmap[cur.Key.ComputeMapKey(store, false)] = cur } return cv case TypeValue: