Skip to content

Commit

Permalink
feat(examples): wugnot (grc20’s wrapped ugnot) (gnolang#1356)
Browse files Browse the repository at this point in the history
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
gnolang#1269](gnolang#1269 (comment)).

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.

<!-- please provide a detailed description of the changes made in this
pull request. -->

<details><summary>Contributors' checklist...</summary>

- [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).
</details>

---------

Signed-off-by: moul <94029+moul@users.noreply.github.com>
  • Loading branch information
moul authored Dec 7, 2023
1 parent 63ff15b commit a338929
Show file tree
Hide file tree
Showing 4 changed files with 250 additions and 0 deletions.
6 changes: 6 additions & 0 deletions examples/gno.land/r/demo/wugnot/gno.mod
Original file line number Diff line number Diff line change
@@ -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
)
126 changes: 126 additions & 0 deletions examples/gno.land/r/demo/wugnot/wugnot.gno
Original file line number Diff line number Diff line change
@@ -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)
}
}
75 changes: 75 additions & 0 deletions examples/gno.land/r/demo/wugnot/z0_filetest.gno
Original file line number Diff line number Diff line change
@@ -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 |
// -----------
43 changes: 43 additions & 0 deletions gno.land/cmd/gnoland/testdata/wugnot.txtar
Original file line number Diff line number Diff line change
@@ -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!'

0 comments on commit a338929

Please sign in to comment.