Skip to content

Commit

Permalink
feat(stdlibs/std)!: namespace minted coins with realm path (gnolang#875)
Browse files Browse the repository at this point in the history
<!-- Please provide a brief summary of your changes in the Title above
-->
# Previous & Related PR
gnolang#393 

# Description
## BREAKING CHANGE: banker will not use raw(input) denom for minting
Currently, there is a bug that additional coins are mintable using
banker.
Lots of discussing were made in gnolang#393, this PR include following.

1. It aims to use `pkg_path` that called (banker or Mint) as prefix for
denom(Similar to IBC Spec)
```
ibc_denom := 'ibc/' + hash('path' + 'base_denom')
denom_in_this_pr := '{pkg_path}:denom'
```

~2. As @piux2 mentioned
[here](gnolang#393 (comment))
currently gno has very inflexible format regexp for denom
-- Changed to same as Cosmos's regex, but without capitals~


~### is some issue about using `std.GetOrigCaller` or `std.PrevRealm`
Some of you might be wonder why I made some packaged called `istd`, I
made a issue: gnolang#876~
Update: After @thehowl's native binding PR, doesn't need this kind of
work around


## 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
- [ ] 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
- [ ] Provided any useful hints for running manual tests

## Maintainers Checklist

- [ ] Checked that the author followed the guidelines in
`CONTRIBUTING.md`
- [ ] Checked the conventional-commit (especially PR title and verb,
presence of `BREAKING CHANGE:` in the body)
- [ ] Ensured that this PR is not a significant change or confirmed that
the review/consideration process was appropriate for the change

---------

Co-authored-by: Morgan <[email protected]>
  • Loading branch information
2 people authored and jefft0 committed May 15, 2024
1 parent 2c5ee76 commit 7d634e3
Show file tree
Hide file tree
Showing 4 changed files with 118 additions and 5 deletions.
88 changes: 88 additions & 0 deletions gno.land/cmd/gnoland/testdata/realm-banker-issued-coin-denom.txtar
Original file line number Diff line number Diff line change
@@ -0,0 +1,88 @@
# test for https://github.com/gnolang/gno/pull/875

## another test user, test2
adduser test2

## start a new node
gnoland start

## add realm_banker
gnokey maketx addpkg -pkgdir $WORK/short -pkgpath gno.land/r/test/realm_banker -gas-fee 1000000ugnot -gas-wanted 10000000 -broadcast -chainid=tendermint_test test1

## add realm_banker with long package_name
gnokey maketx addpkg -pkgdir $WORK/long -pkgpath gno.land/r/test/package89_123456789_123456789_123456789_123456789_123456789_123456789_123456789_123456789_123456789_123456789_123456789_1234567890 -gas-fee 1000000ugnot -gas-wanted 10000000 -broadcast -chainid=tendermint_test test1

## test2 spend all balance
gnokey maketx send -send "9999999ugnot" -to g1jg8mtutu9khhfwc4nxmuhcpftf0pajdhfvsqf5 -gas-fee 1ugnot -gas-wanted 10000000 -broadcast -chainid=tendermint_test test2

## check test2 balance
gnokey query bank/balances/${USER_ADDR_test2}
stdout ''

## mint coin from banker
gnokey maketx call -pkgpath gno.land/r/test/realm_banker -func Mint -args ${USER_ADDR_test2} -args "ugnot" -args "31337" -gas-fee 1000000ugnot -gas-wanted 10000000 -broadcast -chainid=tendermint_test test1

## check balance after minting, without patching banker will return '31337ugnot'
gnokey query bank/balances/${USER_ADDR_test2}
stdout '"31337/gno.land/r/test/realm_banker:ugnot"'

## burn coin
gnokey maketx call -pkgpath gno.land/r/test/realm_banker -func Burn -args ${USER_ADDR_test2} -args "ugnot" -args "7" -gas-fee 1000000ugnot -gas-wanted 10000000 -broadcast -chainid=tendermint_test test1

## check balance after burning
gnokey query bank/balances/${USER_ADDR_test2}
stdout '"31330/gno.land/r/test/realm_banker:ugnot"'

## transfer 1ugnot to test2 for gas-fee of below tx
gnokey maketx send -send "1ugnot" -to ${USER_ADDR_test2} -gas-fee 1ugnot -gas-wanted 10000000 -broadcast -chainid=tendermint_test test1

## transfer coin
gnokey maketx send -send "1330/gno.land/r/test/realm_banker:ugnot" -to g1yr0dpfgthph7y6mepdx8afuec4q3ga2lg8tjt0 -gas-fee 1ugnot -gas-wanted 10000000 -broadcast -chainid=tendermint_test test2

## check sender balance
gnokey query bank/balances/${USER_ADDR_test2}
stdout '"30000/gno.land/r/test/realm_banker:ugnot"'

## check receiver balance
gnokey query bank/balances/g1yr0dpfgthph7y6mepdx8afuec4q3ga2lg8tjt0
stdout '"1330/gno.land/r/test/realm_banker:ugnot"'

## mint coin from long named package with banker
gnokey maketx call -pkgpath gno.land/r/test/package89_123456789_123456789_123456789_123456789_123456789_123456789_123456789_123456789_123456789_123456789_123456789_1234567890 -func Mint -args "g1cq2ecdq3eyn5qa0fzznpurg87zq3k77g63q6u7" -args "ugnot" -args "100" -gas-fee 1000000ugnot -gas-wanted 10000000 -broadcast -chainid=tendermint_test test1
gnokey query bank/balances/g1cq2ecdq3eyn5qa0fzznpurg87zq3k77g63q6u7
stdout '"100/gno.land/r/test/package89_123456789_123456789_123456789_123456789_123456789_123456789_123456789_123456789_123456789_123456789_123456789_1234567890:ugnot"'

-- short/realm_banker.gno --
package realm_banker

import (
"std"
)

func Mint(addr std.Address, denom string, amount int64) {
banker := std.GetBanker(std.BankerTypeRealmIssue)
banker.IssueCoin(addr, denom, amount)
}

func Burn(addr std.Address, denom string, amount int64) {
banker := std.GetBanker(std.BankerTypeRealmIssue)
banker.RemoveCoin(addr, denom, amount)
}

-- long/realm_banker.gno --
// package name is 130 characters long
package package89_123456789_123456789_123456789_123456789_123456789_123456789_123456789_123456789_123456789_123456789_123456789_1234567890

import (
"std"
)

func Mint(addr std.Address, denom string, amount int64) {
banker := std.GetBanker(std.BankerTypeRealmIssue)
banker.IssueCoin(addr, denom, amount)
}

func Burn(addr std.Address, denom string, amount int64) {
banker := std.GetBanker(std.BankerTypeRealmIssue)
banker.RemoveCoin(addr, denom, amount)
}
30 changes: 28 additions & 2 deletions gnovm/stdlibs/std/banker.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ package std

import (
"fmt"
"regexp"

gno "github.com/gnolang/gno/gnovm/pkg/gnolang"
"github.com/gnolang/gno/tm2/pkg/crypto"
Expand Down Expand Up @@ -32,6 +33,11 @@ const (
btRealmIssue
)

// regexp for denom format
const denomRegex = "[a-z][a-z0-9]{2,15}"

var reg = regexp.MustCompile(denomRegex)

func X_bankerGetCoins(m *gno.Machine, bt uint8, addr string) (denoms []string, amounts []int64) {
coins := m.Context.(ExecContext).Banker.GetCoins(crypto.Bech32Address(addr))
return ExpandCoins(coins)
Expand Down Expand Up @@ -88,10 +94,30 @@ func X_bankerTotalCoin(m *gno.Machine, bt uint8, denom string) int64 {

func X_bankerIssueCoin(m *gno.Machine, bt uint8, addr string, denom string, amount int64) {
// gno checks for bt == RealmIssue
m.Context.(ExecContext).Banker.IssueCoin(crypto.Bech32Address(addr), denom, amount)

// check origin denom format
matched := reg.MatchString(denom)
if !matched {
m.Panic(typedString("invalid denom format to issue coin, must be " + denomRegex))
return
}

// Similar to ibc spec
// ibc_denom := 'ibc/' + hash('path' + 'base_denom')
// gno_realm_denom := '/' + 'pkg_path' + ':' + 'base_denom'
newDenom := "/" + m.Realm.Path + ":" + denom
m.Context.(ExecContext).Banker.IssueCoin(crypto.Bech32Address(addr), newDenom, amount)
}

func X_bankerRemoveCoin(m *gno.Machine, bt uint8, addr string, denom string, amount int64) {
// gno checks for bt == RealmIssue
m.Context.(ExecContext).Banker.IssueCoin(crypto.Bech32Address(addr), denom, amount)

matched := reg.MatchString(denom)
if !matched {
m.Panic(typedString("invalid denom format to remove coin, must be " + denomRegex))
return
}

newDenom := "/" + m.Realm.Path + ":" + denom
m.Context.(ExecContext).Banker.RemoveCoin(crypto.Bech32Address(addr), newDenom, amount)
}
3 changes: 1 addition & 2 deletions tm2/pkg/std/coin.go
Original file line number Diff line number Diff line change
Expand Up @@ -616,8 +616,7 @@ func (coins Coins) Sort() Coins {
// Parsing

var (
// Denominations can be 3 ~ 16 characters long.
reDnmString = `[a-z][a-z0-9]{2,15}`
reDnmString = `[a-z\/][a-z0-9_.:\/]{2,}`
reAmt = `[[:digit:]]+`
reSpc = `[[:space:]]*`
reDnm = regexp.MustCompile(fmt.Sprintf(`^%s$`, reDnmString))
Expand Down
2 changes: 1 addition & 1 deletion tm2/pkg/std/coin_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -429,11 +429,11 @@ func TestParse(t *testing.T) {
{"98 bar , 1 foo ", true, Coins{{"bar", int64(98)}, {"foo", one}}},
{" 55\t \t bling\n", true, Coins{{"bling", int64(55)}}},
{"2foo, 97 bar", true, Coins{{"bar", int64(97)}, {"foo", int64(2)}}},
{"5foo-bar", false, nil},
{"5 mycoin,", false, nil}, // no empty coins in a list
{"2 3foo, 97 bar", false, nil}, // 3foo is invalid coin name
{"11me coin, 12you coin", false, nil}, // no spaces in coin names
{"1.2btc", false, nil}, // amount must be integer
{"5foo-bar", false, nil}, // once more, only letters in coin name
}

for tcIndex, tc := range cases {
Expand Down

0 comments on commit 7d634e3

Please sign in to comment.