From 04d955c12d54ddd8e8c5a446ec11268ed3eb5eb1 Mon Sep 17 00:00:00 2001 From: n3wbie Date: Sat, 21 Oct 2023 10:19:28 -0400 Subject: [PATCH 1/4] 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 8bd6d63d65acca55a776e5a46488721e62450525 Mon Sep 17 00:00:00 2001 From: n3wbie Date: Sat, 21 Oct 2023 11:15:31 -0400 Subject: [PATCH 2/4] 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 db055968af66a52f52aa1643069b386b7734ccc3 Mon Sep 17 00:00:00 2001 From: n3wbie Date: Thu, 7 Dec 2023 14:08:05 +0900 Subject: [PATCH 3/4] 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 900da316e425bbdc03da75d77082982041b3d707 Mon Sep 17 00:00:00 2001 From: n3wbie Date: Thu, 7 Dec 2023 14:35:49 +0900 Subject: [PATCH 4/4] 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()