Skip to content

Commit

Permalink
feat(examples): refactor grc20 (#2529)
Browse files Browse the repository at this point in the history
Main changes:
- rename `AdminToken` -> `Banker`
- rename `GRC20` -> `Token`
- remove unused helpers
- remove vault (temporarily, will be reimplemented)
- remove the returner ˋerror` when unnecessary
- use `std.Emit`
- use uassert for testing
- better file naming and organization for improved readability

Fixes #2294
Replaces #2314 (h/t @leohhhn)
~Depends on #2534~
BREAKING CHANGE

---------

Signed-off-by: moul <[email protected]>
Co-authored-by: Leon Hudak <[email protected]>
  • Loading branch information
moul and leohhhn committed Jul 7, 2024
1 parent 0e48a76 commit 3affd95
Show file tree
Hide file tree
Showing 35 changed files with 681 additions and 1,189 deletions.
13 changes: 9 additions & 4 deletions docs/assets/how-to-guides/creating-grc20/mytoken-1.gno
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
package mytoken

import (
"std"
"strings"
Expand All @@ -7,7 +9,8 @@ import (
)

var (
mytoken *grc20.AdminToken
banker *grc20.Banker
mytoken grc20.Token
admin std.Address
)

Expand All @@ -17,9 +20,11 @@ func init() {
admin = std.PrevRealm().Addr()

// Set token name, symbol and number of decimals
mytoken = grc20.NewAdminToken("My Token", "TKN", 4)
banker = grc20.NewBanker("My Token", "TKN", 4)

// Mint 1 million tokens to admin
mytoken.Mint(admin, 1000000*10000)
}
banker.Mint(admin, 1_000_000*10_000) // 1M

// Get the GRC20 compatible safe object
mytoken = banker.Token()
}
82 changes: 30 additions & 52 deletions docs/assets/how-to-guides/creating-grc20/mytoken-2.gno
Original file line number Diff line number Diff line change
@@ -1,3 +1,12 @@
package mytoken

import (
"std"
"strings"

"gno.land/p/demo/ufmt"
)

// TotalSupply returns the total supply of mytoken
func TotalSupply() uint64 {
return mytoken.TotalSupply()
Expand All @@ -10,84 +19,39 @@ func Decimals() uint {

// BalanceOf returns the balance mytoken for `account`
func BalanceOf(account std.Address) uint64 {
balance, err := mytoken.BalanceOf(account)
if err != nil {
panic(err)
}

return balance
return mytoken.BalanceOf(account)
}

// Allowance returns the allowance of spender on owner's balance
func Allowance(owner, spender std.Address) uint64 {
allowance, err := mytoken.Allowance(owner, spender)
if err != nil {
panic(err)
}

return allowance
return mytoken.Allowance(owner, spender)
}

// Transfer transfers amount from caller to recipient
func Transfer(recipient std.Address, amount uint64) {
caller := std.PrevRealm().Addr()
if err := mytoken.Transfer(caller, recipient, amount); err != nil {
panic(err)
}
checkErr(mytoken.Transfer(recipient, amount))
}

// Approve approves amount of caller's tokens to be spent by spender
func Approve(spender std.Address, amount uint64) {
caller := std.PrevRealm().Addr()
if err := mytoken.Approve(caller, spender, amount); err != nil {
panic(err)
}
checkErr(mytoken.Approve(spender, amount))
}

// TransferFrom transfers `amount` of tokens from `from` to `to`
func TransferFrom(from, to std.Address, amount uint64) {
caller := std.PrevRealm().Addr()

if amount <= 0 {
panic("transfer amount must be greater than zero")
}

if err := mytoken.TransferFrom(caller, from, to, amount); err != nil {
panic(err)
}
checkErr(mytoken.TransferFrom(from, to, amount))
}

// Mint mints amount of tokens to address. Callable only by admin of token
func Mint(address std.Address, amount uint64) {
assertIsAdmin(std.PrevRealm().Addr())

if amount <= 0 {
panic("mint amount must be greater than zero")
}

if err := mytoken.Mint(address, amount); err != nil {
panic(err)
}
checkErr(banker.Mint(address, amount))
}

// Burn burns amount of tokens from address. Callable only by admin of token
func Burn(address std.Address, amount uint64) {
assertIsAdmin(std.PrevRealm().Addr())

if amount <= 0 {
panic("burn amount must be greater than zero")
}

if err := mytoken.Burn(address, amount); err != nil {
panic(err)
}
}

// assertIsAdmin asserts the address is the admin of token
func assertIsAdmin(address std.Address) {
if address != admin {
panic("restricted access")
}
checkErr(banker.Burn(address, amount))
}

// Render renders the state of the realm
Expand All @@ -108,3 +72,17 @@ func Render(path string) string {
return "404\n"
}
}

// assertIsAdmin asserts the address is the admin of token
func assertIsAdmin(address std.Address) {
if address != admin {
panic("restricted access")
}
}

// checkErr asserts the function didn't returned an error
func checkErr(err error) {
if err != nil {
panic(err)
}
}
5 changes: 2 additions & 3 deletions docs/concepts/effective-gno.md
Original file line number Diff line number Diff line change
Expand Up @@ -701,12 +701,11 @@ best of both worlds, you can wrap a Coins into a GRC20 compatible token.
```go
import "gno.land/p/demo/grc/grc20"

var fooToken grc20.AdminToken = grc20.NewAdminToken("Foo Token", "FOO", 4)
var fooToken = grc20.NewBanker("Foo Token", "FOO", 4)

func MyBalance() uint64 {
caller := std.PrevRealm().Addr()
balance, _ := fooToken.BalanceOf(caller)
return balance
return fooToken.BalanceOf(caller)
}
```

Expand Down
10 changes: 5 additions & 5 deletions docs/concepts/packages.md
Original file line number Diff line number Diff line change
Expand Up @@ -41,12 +41,12 @@ The role of each function is as follows:

Two types of contracts exist in`grc20`:

1. `AdminToken`
1. `Banker`
- Implements the token factory with `Helper` functions.
- The underlying struct should not be exposed to users. However, it can be typecasted as UserToken using the `GRC20()` method.
2. `UserToken`
- Implements the `IGRC20` interface.
- The underlying struct can be exposed to users. Created with the `GRC20()` method of `adminToken`.
- The underlying struct should not be exposed to users. However, it can return a typecasted `Token` object using the `Token()` method.
2. `Token`
- Implements the `GRC20` interface.
- The underlying struct can be exposed to users. Created with the `Token()` method of `Banker`.

## `grc721`

Expand Down
Loading

0 comments on commit 3affd95

Please sign in to comment.