Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat(stdlibs/std)!: namespace minted coins with realm path #875

Merged
merged 16 commits into from
May 14, 2024
Merged
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'
thehowl marked this conversation as resolved.
Show resolved Hide resolved
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)
}
28 changes: 26 additions & 2 deletions gnovm/stdlibs/std/banker.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@

import (
"fmt"
"regexp"

gno "github.com/gnolang/gno/gnovm/pkg/gnolang"
"github.com/gnolang/gno/tm2/pkg/crypto"
Expand Down Expand Up @@ -30,6 +31,9 @@
btRealmSend
// Can issue and remove realm coins.
btRealmIssue

// regexp for denom format
denomRegex = "[a-z][a-z0-9]{2,15}"
zivkovicmilos marked this conversation as resolved.
Show resolved Hide resolved
)

func X_bankerGetCoins(m *gno.Machine, bt uint8, addr string) (denoms []string, amounts []int64) {
Expand Down Expand Up @@ -88,10 +92,30 @@

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, err := regexp.MatchString(denomRegex, denom)
zivkovicmilos marked this conversation as resolved.
Show resolved Hide resolved
if err != nil || !matched {
m.Panic(typedString("invalid denom format to issue coin, must be " + denomRegex))
return

Check warning on line 100 in gnovm/stdlibs/std/banker.go

View check run for this annotation

Codecov / codecov/patch

gnovm/stdlibs/std/banker.go#L97-L100

Added lines #L97 - L100 were not covered by tests
}

// 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)

Check warning on line 107 in gnovm/stdlibs/std/banker.go

View check run for this annotation

Codecov / codecov/patch

gnovm/stdlibs/std/banker.go#L106-L107

Added lines #L106 - L107 were not covered by tests
}

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, err := regexp.MatchString(denomRegex, denom)
if err != nil || !matched {
m.Panic(typedString("invalid denom format to remove coin, must be " + denomRegex))
return

Check warning on line 116 in gnovm/stdlibs/std/banker.go

View check run for this annotation

Codecov / codecov/patch

gnovm/stdlibs/std/banker.go#L113-L116

Added lines #L113 - L116 were not covered by tests
}

newDenom := "/" + m.Realm.Path + ":" + denom
m.Context.(ExecContext).Banker.RemoveCoin(crypto.Bech32Address(addr), newDenom, amount)

Check warning on line 120 in gnovm/stdlibs/std/banker.go

View check run for this annotation

Codecov / codecov/patch

gnovm/stdlibs/std/banker.go#L119-L120

Added lines #L119 - L120 were not covered by tests
}
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
Loading