From a338929c764bd72f04283f8ec2e691c4d426ca97 Mon Sep 17 00:00:00 2001 From: Manfred Touron <94029+moul@users.noreply.github.com> Date: Thu, 7 Dec 2023 23:19:35 +0100 Subject: [PATCH] =?UTF-8?q?feat(examples):=20wugnot=20(grc20=E2=80=99s=20w?= =?UTF-8?q?rapped=20ugnot)=20(#1356)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This PR presents a GNOT wrapper that conforms to the GRC20 interface. Optimally, the txtar file should be relocated to the wugnot directory, pending resolution of [issue #1269](https://github.com/gnolang/gno/issues/1269#issuecomment-1806386069). Enabling the use of `gnokey maketx call -func WUGNOT.Transfer` over `-func Transfer` would streamline the wrapper, reducing it to just the initial 55 lines.
Contributors' checklist... - [x] Added new tests, or not needed, or not feasible - [x] Provided an example (e.g. screenshot) to aid review or the PR is self-explanatory - [x] Updated the official documentation or not needed - [x] No breaking changes were made, or a `BREAKING CHANGE: xxx` message was included in the description - [x] Added references to related issues and PRs - [x] Provided any useful hints for running manual tests - [x] Added new benchmarks to [generated graphs](https://gnoland.github.io/benchmarks), if any. More info [here](https://github.com/gnolang/gno/blob/master/.benchmarks/README.md).
--------- Signed-off-by: moul <94029+moul@users.noreply.github.com> --- examples/gno.land/r/demo/wugnot/gno.mod | 6 + examples/gno.land/r/demo/wugnot/wugnot.gno | 126 ++++++++++++++++++ .../gno.land/r/demo/wugnot/z0_filetest.gno | 75 +++++++++++ gno.land/cmd/gnoland/testdata/wugnot.txtar | 43 ++++++ 4 files changed, 250 insertions(+) create mode 100644 examples/gno.land/r/demo/wugnot/gno.mod create mode 100644 examples/gno.land/r/demo/wugnot/wugnot.gno create mode 100644 examples/gno.land/r/demo/wugnot/z0_filetest.gno create mode 100644 gno.land/cmd/gnoland/testdata/wugnot.txtar diff --git a/examples/gno.land/r/demo/wugnot/gno.mod b/examples/gno.land/r/demo/wugnot/gno.mod new file mode 100644 index 00000000000..1f03ded515c --- /dev/null +++ b/examples/gno.land/r/demo/wugnot/gno.mod @@ -0,0 +1,6 @@ +module gno.land/r/demo/wugnot + +require ( + gno.land/p/demo/grc/grc20 v0.0.0-latest + gno.land/p/demo/ufmt v0.0.0-latest +) diff --git a/examples/gno.land/r/demo/wugnot/wugnot.gno b/examples/gno.land/r/demo/wugnot/wugnot.gno new file mode 100644 index 00000000000..82c3c43db89 --- /dev/null +++ b/examples/gno.land/r/demo/wugnot/wugnot.gno @@ -0,0 +1,126 @@ +package wugnot + +import ( + "std" + "strings" + + "gno.land/p/demo/grc/grc20" + "gno.land/p/demo/ufmt" +) + +var ( + // wugnot is the admin token, able to mint and burn. + wugnot *grc20.AdminToken = grc20.NewAdminToken("wrapped GNOT", "wugnot", 0) + // WUGNOT is the banker usable by users directly. + WUGNOT = wugnot.GRC20() +) + +const ( + ugnotMinDeposit uint64 = 1000 + wugnotMinDeposit uint64 = 1 +) + +// wrapper. +// + +func Deposit() { + caller := std.PrevRealm().Addr() + sent := std.GetOrigSend() + amount := sent.AmountOf("ugnot") + + if uint64(amount) < ugnotMinDeposit { + panic(ufmt.Sprintf("Deposit below minimum: %d/%d ugnot.", amount, ugnotMinDeposit)) + } + wugnot.Mint(caller, uint64(amount)) +} + +func Withdraw(amount uint64) { + if amount < wugnotMinDeposit { + panic(ufmt.Sprintf("Deposit below minimum: %d/%d wugnot.", amount, wugnotMinDeposit)) + } + + caller := std.PrevRealm().Addr() + pkgaddr := std.GetOrigPkgAddr() + + callerBal, _ := wugnot.BalanceOf(caller) + if callerBal < amount { + panic(ufmt.Sprintf("Insufficient balance: %d available, %d needed.", callerBal, amount)) + } + + // send swapped ugnots to caller + banker := std.GetBanker(std.BankerTypeRealmSend) + send := std.Coins{{"ugnot", int64(amount)}} + banker.SendCoins(pkgaddr, caller, send) + wugnot.Burn(caller, amount) +} + +// render. +// + +func Render(path string) string { + parts := strings.Split(path, "/") + c := len(parts) + + switch { + case path == "": + return wugnot.RenderHome() + case c == 2 && parts[0] == "balance": + owner := std.Address(parts[1]) + balance, _ := wugnot.BalanceOf(owner) + return ufmt.Sprintf("%d\n", balance) + default: + return "404\n" + } +} + +// XXX: if we could call WUGNOT.XXX instead of XXX from gnokey, then, all the following lines would not be needed. + +// direct getters. +// XXX: remove them in favor of q_call wugnot.XXX + +func TotalSupply() uint64 { + return wugnot.TotalSupply() +} + +func BalanceOf(owner std.Address) uint64 { + balance, err := wugnot.BalanceOf(owner) + if err != nil { + panic(err) + } + return balance +} + +func Allowance(owner, spender std.Address) uint64 { + allowance, err := wugnot.Allowance(owner, spender) + if err != nil { + panic(err) + } + return allowance +} + +// setters. +// + +func Transfer(to std.Address, amount uint64) { + caller := std.PrevRealm().Addr() + err := wugnot.Transfer(caller, to, amount) + if err != nil { + panic(err) + } +} + +func Approve(spender std.Address, amount uint64) { + caller := std.PrevRealm().Addr() + err := wugnot.Approve(caller, spender, amount) + if err != nil { + panic(err) + } +} + +func TransferFrom(from, to std.Address, amount uint64) { + caller := std.PrevRealm().Addr() + err := wugnot.TransferFrom(caller, from, to, amount) + if err != nil { + panic(err) + } +} diff --git a/examples/gno.land/r/demo/wugnot/z0_filetest.gno b/examples/gno.land/r/demo/wugnot/z0_filetest.gno new file mode 100644 index 00000000000..fa2f45682b1 --- /dev/null +++ b/examples/gno.land/r/demo/wugnot/z0_filetest.gno @@ -0,0 +1,75 @@ +// PKGPATH: gno.land/r/demo/wugnot_test +package wugnot_test + +import ( + "fmt" + "std" + + "gno.land/p/demo/testutils" + "gno.land/r/demo/wugnot" +) + +var ( + addr1 = testutils.TestAddress("test1") + addrc = std.DerivePkgAddr("gno.land/r/demo/wugnot") + addrt = std.DerivePkgAddr("gno.land/r/demo/wugnot_test") +) + +func main() { + std.TestSetOrigPkgAddr(addrc) + std.TestIssueCoins(addrc, std.Coins{{"ugnot", 100000001}}) // TODO: remove this + + // issue ugnots + std.TestIssueCoins(addr1, std.Coins{{"ugnot", 100000001}}) + + // print initial state + printBalances() + // println(wugnot.Render("queues")) + // println("A -", wugnot.Render("")) + + std.TestSetOrigCaller(addr1) + std.TestSetOrigSend(std.Coins{{"ugnot", 123_400}}, nil) + wugnot.Deposit() + printBalances() + wugnot.Withdraw(4242) + printBalances() +} + +func printBalances() { + printSingleBalance := func(name string, addr std.Address) { + wugnotBal := wugnot.BalanceOf(addr) + std.TestSetOrigCaller(addr) + abanker := std.GetBanker(std.BankerTypeOrigSend) + acoins := abanker.GetCoins(addr).AmountOf("ugnot") + bbanker := std.GetBanker(std.BankerTypeRealmIssue) + bcoins := bbanker.GetCoins(addr).AmountOf("ugnot") + cbanker := std.GetBanker(std.BankerTypeRealmSend) + ccoins := cbanker.GetCoins(addr).AmountOf("ugnot") + dbanker := std.GetBanker(std.BankerTypeReadonly) + dcoins := dbanker.GetCoins(addr).AmountOf("ugnot") + fmt.Printf("| %-13s | addr=%s | wugnot=%-5d | ugnot=%-9d %-9d %-9d %-9d |\n", + name, addr, wugnotBal, acoins, bcoins, ccoins, dcoins) + } + println("-----------") + printSingleBalance("wugnot_test", addrt) + printSingleBalance("wugnot", addrc) + printSingleBalance("addr1", addr1) + println("-----------") +} + +// Output: +// ----------- +// | wugnot_test | addr=g19rmydykafrqyyegc8uuaxxpzqwzcnxraj2dev9 | wugnot=0 | ugnot=200000000 200000000 200000000 200000000 | +// | wugnot | addr=g1pf6dv9fjk3rn0m4jjcne306ga4he3mzmupfjl6 | wugnot=0 | ugnot=100000001 100000001 100000001 100000001 | +// | addr1 | addr=g1w3jhxap3ta047h6lta047h6lta047h6l4mfnm7 | wugnot=0 | ugnot=100000001 100000001 100000001 100000001 | +// ----------- +// ----------- +// | wugnot_test | addr=g19rmydykafrqyyegc8uuaxxpzqwzcnxraj2dev9 | wugnot=123400 | ugnot=200000000 200000000 200000000 200000000 | +// | wugnot | addr=g1pf6dv9fjk3rn0m4jjcne306ga4he3mzmupfjl6 | wugnot=0 | ugnot=100000001 100000001 100000001 100000001 | +// | addr1 | addr=g1w3jhxap3ta047h6lta047h6lta047h6l4mfnm7 | wugnot=0 | ugnot=100000001 100000001 100000001 100000001 | +// ----------- +// ----------- +// | wugnot_test | addr=g19rmydykafrqyyegc8uuaxxpzqwzcnxraj2dev9 | wugnot=119158 | ugnot=200004242 200004242 200004242 200004242 | +// | wugnot | addr=g1pf6dv9fjk3rn0m4jjcne306ga4he3mzmupfjl6 | wugnot=0 | ugnot=99995759 99995759 99995759 99995759 | +// | addr1 | addr=g1w3jhxap3ta047h6lta047h6lta047h6l4mfnm7 | wugnot=0 | ugnot=100000001 100000001 100000001 100000001 | +// ----------- diff --git a/gno.land/cmd/gnoland/testdata/wugnot.txtar b/gno.land/cmd/gnoland/testdata/wugnot.txtar new file mode 100644 index 00000000000..5c2d7d3cb90 --- /dev/null +++ b/gno.land/cmd/gnoland/testdata/wugnot.txtar @@ -0,0 +1,43 @@ +gnoland start + +gnokey maketx call -pkgpath gno.land/r/demo/wugnot -func Render -gas-fee 1000000ugnot -gas-wanted 2000000 -args '' -broadcast -chainid=tendermint_test test1 +stdout '# wrapped GNOT \(\$wugnot\)' +stdout 'Decimals..: 0' +stdout 'Total supply..: 0' +stdout 'Known accounts..: 0' +stdout 'OK!' + +gnokey maketx call -pkgpath gno.land/r/demo/wugnot -func Deposit -send 12345678ugnot -gas-fee 1000000ugnot -gas-wanted 2000000 -broadcast -chainid=tendermint_test test1 +stdout 'OK!' + +gnokey maketx call -pkgpath gno.land/r/demo/wugnot -func Render -gas-fee 1000000ugnot -gas-wanted 2000000 -args '' -broadcast -chainid=tendermint_test test1 +stdout 'Total supply..: 12345678' +stdout 'Known accounts..: 1' +stdout 'OK!' + +# XXX: use test2 instead (depends on https://github.com/gnolang/gno/issues/1269#issuecomment-1806386069) +gnokey maketx call -pkgpath gno.land/r/demo/wugnot -func Deposit -send 12345678ugnot -gas-fee 1000000ugnot -gas-wanted 2000000 -broadcast -chainid=tendermint_test test1 +stdout 'OK!' + +gnokey maketx call -pkgpath gno.land/r/demo/wugnot -func Render -gas-fee 1000000ugnot -gas-wanted 2000000 -args '' -broadcast -chainid=tendermint_test test1 +stdout 'Total supply..: 24691356' +stdout 'Known accounts..: 1' # should be 2 once we can use test2 +stdout 'OK!' + +# XXX: replace hardcoded address with test3 +gnokey maketx call -pkgpath gno.land/r/demo/wugnot -func Transfer -gas-fee 1000000ugnot -gas-wanted 2000000 -args 'g1u7y667z64x2h7vc6fmpcprgey4ck233jaww9zq' -args '10000000' -broadcast -chainid=tendermint_test test1 +stdout 'OK!' + +gnokey maketx call -pkgpath gno.land/r/demo/wugnot -func Render -gas-fee 1000000ugnot -gas-wanted 2000000 -args '' -broadcast -chainid=tendermint_test test1 +stdout 'Total supply..: 24691356' +stdout 'Known accounts..: 2' # should be 3 once we can use test2 +stdout 'OK!' + +# XXX: use test3 instead (depends on https://github.com/gnolang/gno/issues/1269#issuecomment-1806386069) +gnokey maketx call -pkgpath gno.land/r/demo/wugnot -func Withdraw -args 10000000 -gas-fee 1000000ugnot -gas-wanted 2000000 -broadcast -chainid=tendermint_test test1 +stdout 'OK!' + +gnokey maketx call -pkgpath gno.land/r/demo/wugnot -func Render -gas-fee 1000000ugnot -gas-wanted 2000000 -args '' -broadcast -chainid=tendermint_test test1 +stdout 'Total supply..: 14691356' +stdout 'Known accounts..: 2' # should be 3 once we can use test2 +stdout 'OK!'