Skip to content

Commit

Permalink
feat(gnovm): add Coin constructor and more functionality (#2104)
Browse files Browse the repository at this point in the history
<!-- please provide a detailed description of the changes made in this
pull request. -->

## Description

This PR ports more functionality from
[coin.go](https://github.com/gnolang/gno/blob/master/tm2/pkg/std/coin.go?rgh-link-date=2024-02-27T11%3A01%3A45Z),
into Gno (std & stdshim). It will also update the concept & reference
docs for Coins.

Superseding #1696

<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
- [ ] 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>

---------

Co-authored-by: Morgan <[email protected]>
  • Loading branch information
leohhhn and thehowl authored May 27, 2024
1 parent ff61f86 commit 3ec2f72
Show file tree
Hide file tree
Showing 14 changed files with 502 additions and 37 deletions.
148 changes: 142 additions & 6 deletions docs/reference/stdlibs/std/coin.md
Original file line number Diff line number Diff line change
Expand Up @@ -10,31 +10,167 @@ type Coin struct {
Denom string `json:"denom"`
Amount int64 `json:"amount"`
}

func NewCoin(denom string, amount int64) Coin {...}
func (c Coin) String() string {...}
func (c Coin) IsGTE(other Coin) bool {...}
func (c Coin) IsLT(other Coin) bool {...}
func (c Coin) IsEqual(other Coin) bool {...}
func (c Coin) Add(other Coin) Coin {...}
func (c Coin) Sub(other Coin) Coin {...}
func (c Coin) IsPositive() bool {...}
func (c Coin) IsNegative() bool {...}
func (c Coin) IsZero() bool {...}
```

## NewCoin
Returns a new Coin with a specific denomination and amount.

#### Usage
```go
coin := std.NewCoin("ugnot", 100)
```
---

## String
Returns a string representation of the `Coin` it was called upon.

#### Usage
```go
coin := std.Coin{"ugnot", 100}
coin := std.NewCoin("ugnot", 100)
coin.String() // 100ugnot
```
---

## IsGTE
Checks if the amount of `other` Coin is greater or equal than amount of Coin `c` it was called upon.
If coins compared are not of the same denomination, `IsGTE` will panic.
Checks if the amount of `other` Coin is greater than or equal than amount of
Coin `c` it was called upon. If coins compared are not of the same denomination,
`IsGTE` will panic.

#### Parameters
- `other` **Coin** to compare with

#### Usage
```go
coin1 := std.Coin{"ugnot", 150}
coin2 := std.Coin{"ugnot", 100}
coin1 := std.NewCoin("ugnot", 150)
coin2 := std.NewCoin("ugnot", 100)

coin1.IsGTE(coin2) // true
coin2.IsGTE(coin1) // false
```
```
---

## IsLT
Checks if the amount of `other` Coin is less than the amount of Coin `c` it was
called upon. If coins compared are not of the same denomination, `IsLT` will
panic.

#### Parameters
- `other` **Coin** to compare with

#### Usage
```go
coin := std.NewCoin("ugnot", 150)
coin := std.NewCoin("ugnot", 100)

coin1.IsLT(coin2) // false
coin2.IsLT(coin1) // true
```
---

## IsEqual
Checks if the amount of `other` Coin is equal to the amount of Coin `c` it was
called upon. If coins compared are not of the same denomination, `IsEqual` will
panic.

#### Parameters
- `other` **Coin** to compare with

#### Usage
```go
coin1 := std.NewCoin("ugnot", 150)
coin2 := std.NewCoin("ugnot", 100)
coin3 := std.NewCoin("ugnot", 100)

coin1.IsEqual(coin2) // false
coin2.IsEqual(coin1) // false
coin2.IsEqual(coin3) // true
```
---

## Add
Adds two coins of the same denomination. If coins are not of the same
denomination, `Add` will panic. If final amount is larger than the maximum size
of `int64`, `Add` will panic with an overflow error. Adding a negative amount
will result in subtraction.

#### Parameters
- `other` **Coin** to add

#### Usage
```go
coin1 := std.NewCoin("ugnot", 150)
coin2 := std.NewCoin("ugnot", 100)

coin3 := coin1.Add(coin2)
coin3.String() // 250ugnot
```
---

## Sub
Subtracts two coins of the same denomination. If coins are not of the same
denomination, `Sub` will panic. If final amount is smaller than the minimum size
of `int64`, `Sub` will panic with an underflow error. Subtracting a negative amount
will result in addition.

#### Parameters
- `other` **Coin** to subtract

#### Usage
```go
coin1 := std.NewCoin("ugnot", 150)
coin2 := std.NewCoin("ugnot", 100)

coin3 := coin1.Sub(coin2)
coin3.String() // 50ugnot
```
---

## IsPositive
Checks if a coin amount is positive.

#### Usage
```go
coin1 := std.NewCoin("ugnot", 150)
coin2 := std.NewCoin("ugnot", -150)

coin1.IsPositive() // true
coin2.IsPositive() // false
```
---

## IsNegative
Checks if a coin amount is negative.

#### Usage
```go
coin1 := std.NewCoin("ugnot", 150)
coin2 := std.NewCoin("ugnot", -150)

coin1.IsNegative() // false
coin2.IsNegative() // true
```
---

## IsZero
Checks if a coin amount is zero.

#### Usage
```go
coin1 := std.NewCoin("ugnot", 150)
coin2 := std.NewCoin("ugnot", 0)

coin1.IsZero() // false
coin2.IsZero() // true
```

17 changes: 17 additions & 0 deletions docs/reference/stdlibs/std/coins.md
Original file line number Diff line number Diff line change
Expand Up @@ -8,11 +8,28 @@ id: coins

```go
type Coins []Coin

func NewCoins(coins ...Coin) Coins {...}
func (c Coins) String() string {...}
func (c Coins) AmountOf(denom string) int64 {...}
func (c Coins) Add(other Coins) Coins {...}
```

### NewCoins
Returns a new set of `Coins` given one or more `Coin`. Consolidates any denom
duplicates into one, keeping the properties of a mathematical set.

#### Usage
```go
coin1 := std.NewCoin("ugnot", 150)
coin2 := std.NewCoin("example", 100)
coin3 := std.NewCoin("ugnot", 100)

coins := std.NewCoins(coin1, coin2, coin3)
coins.String() // 250ugnot, 100example
```
---

### String
Returns a string representation of the `Coins` set it was called upon.

Expand Down
2 changes: 1 addition & 1 deletion examples/gno.land/r/demo/boards/public.gno
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,7 @@ func CreateBoard(name string) BoardID {

func checkAnonFee() bool {
sent := std.GetOrigSend()
anonFeeCoin := std.Coin{"ugnot", int64(gDefaultAnonFee)}
anonFeeCoin := std.NewCoin("ugnot", int64(gDefaultAnonFee))
if len(sent) == 1 && sent[0].IsGTE(anonFeeCoin) {
return true
}
Expand Down
2 changes: 1 addition & 1 deletion examples/gno.land/r/demo/users/users.gno
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,7 @@ func Register(inviter std.Address, name string, profile string) {
panic("should not happen") // because std.AssertOrigCall().
}
sentCoins := std.GetOrigSend()
minCoin := std.Coin{"ugnot", minFee}
minCoin := std.NewCoin("ugnot", minFee)
if inviter == "" {
// banker := std.GetBanker(std.BankerTypeOrigSend)
if len(sentCoins) == 1 && sentCoins[0].IsGTE(minCoin) {
Expand Down
4 changes: 2 additions & 2 deletions examples/gno.land/r/demo/users/z_0_filetest.gno
Original file line number Diff line number Diff line change
Expand Up @@ -7,10 +7,10 @@ import (
)

func main() {
std.TestSetOrigSend(std.Coins{{"dontcare", 1}}, nil)
std.TestSetOrigSend(std.Coins{std.NewCoin("dontcare", 1)}, nil)
users.Register("", "gnouser", "my profile")
println("done")
}

// Error:
// invalid coin denominations: dontcare
// incompatible coin denominations: dontcare, ugnot
2 changes: 1 addition & 1 deletion examples/gno.land/r/gnoland/faucet/admin.gno
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@ func AdminSetTransferLimit(amount int64) string {
if err := assertIsAdmin(); err != nil {
return err.Error()
}
gLimit = std.Coin{Denom: "ugnot", Amount: amount}
gLimit = std.NewCoin("ugnot", amount)
return ""
}

Expand Down
4 changes: 2 additions & 2 deletions examples/gno.land/r/gnoland/faucet/faucet.gno
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@ var (
gTotalTransfers = uint(0)

// per request limit, 350 gnot
gLimit std.Coin = std.Coin{"ugnot", 350000000}
gLimit std.Coin = std.NewCoin("ugnot", 350000000)
)

func Transfer(to std.Address, send int64) string {
Expand All @@ -37,7 +37,7 @@ func Transfer(to std.Address, send int64) string {
if send > gLimit.Amount {
return errors.New("Per request limit " + gLimit.String() + " exceed").Error()
}
sendCoins := std.Coins{std.Coin{Denom: "ugnot", Amount: send}}
sendCoins := std.Coins{std.NewCoin("ugnot", send)}

gTotalTransferred = gTotalTransferred.Add(sendCoins)
gTotalTransfers++
Expand Down
2 changes: 1 addition & 1 deletion gno.land/cmd/gnoland/testdata/issue_1786.txtar
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ loadpkg gno.land/r/demo/wugnot
gnoland start

# add contract
gnokey maketx addpkg -pkgdir $WORK -pkgpath gno.land/r/demo/proxywugnot -gas-fee 1000000ugnot -gas-wanted 4000000 -broadcast -chainid=tendermint_test test1
gnokey maketx addpkg -pkgdir $WORK -pkgpath gno.land/r/demo/proxywugnot -gas-fee 1000000ugnot -gas-wanted 6000000 -broadcast -chainid=tendermint_test test1
stdout OK!

# approve wugnot to `proxywugnot ≈ g1fndyg0we60rdfchyy5dwxzkfmhl5u34j932rg3`
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,10 +7,10 @@ adduser test2
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
gnokey maketx addpkg -pkgdir $WORK/short -pkgpath gno.land/r/test/realm_banker -gas-fee 1000000ugnot -gas-wanted 100000000 -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
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 100000000 -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
Expand Down
86 changes: 86 additions & 0 deletions gno.land/pkg/integration/testdata/improved-coins.txtar
Original file line number Diff line number Diff line change
@@ -0,0 +1,86 @@
loadpkg gno.land/r/demo/coins $WORK

gnoland start

gnokey maketx call -pkgpath gno.land/r/demo/coins -func "MakeNewCoins" -gas-fee 1000000ugnot -gas-wanted 2000000 -broadcast -chainid=tendermint_test test1
stdout '(300 int64)'
stdout '(321 int64)'
stdout '("ugnot" string)'
stdout '("example" string)'

gnokey maketx call -pkgpath gno.land/r/demo/coins -func "AddCoin" -gas-fee 1000000ugnot -gas-wanted 2000000 -broadcast -chainid=tendermint_test test1
stdout '(300 int64)'

gnokey maketx call -pkgpath gno.land/r/demo/coins -func "SubCoin" -gas-fee 1000000ugnot -gas-wanted 2000000 -broadcast -chainid=tendermint_test test1
stdout '(123 int64)'

gnokey maketx call -pkgpath gno.land/r/demo/coins -func "StringZeroCoin" -gas-fee 1000000ugnot -gas-wanted 2000000 -broadcast -chainid=tendermint_test test1
stdout '("0ugnot" string)'

gnokey maketx call -pkgpath gno.land/r/demo/coins -func "IsZero" -gas-fee 1000000ugnot -gas-wanted 2000000 -broadcast -chainid=tendermint_test test1
stdout '(true bool)'
stdout '(false bool)'
stdout '(false bool)'

gnokey maketx call -pkgpath gno.land/r/demo/coins -func "IsPositive" -gas-fee 1000000ugnot -gas-wanted 2000000 -broadcast -chainid=tendermint_test test1
stdout '(false bool)'
stdout '(false bool)'
stdout '(true bool)'

gnokey maketx call -pkgpath gno.land/r/demo/coins -func "IsNegative" -gas-fee 1000000ugnot -gas-wanted 2000000 -broadcast -chainid=tendermint_test test1
stdout '(true bool)'
stdout '(false bool)'
stdout '(false bool)'

-- coins.gno --
package coins

import "std"

func MakeNewCoins() std.Coins {
coin1 := std.NewCoin("ugnot", 123)
coin2 := std.NewCoin("example", 321)
coin3 := std.NewCoin("ugnot", 177)


return std.NewCoins(coin1, coin2, coin3)
}

func AddCoin() std.Coin {
coin1 := std.NewCoin("ugnot", 123)
coin2 := std.NewCoin("ugnot", 177)
return coin1.Add(coin2)
}

func SubCoin() std.Coin {
coin1 := std.NewCoin("ugnot", 300)
coin2 := std.NewCoin("ugnot", 177)
return coin1.Sub(coin2)
}

func StringZeroCoin() string {
coin1 := std.NewCoin("ugnot", 0)
return coin1.String()
}

func IsZero() (bool, bool, bool) {
coin1 := std.NewCoin("ugnot", 0)
coin2 := std.NewCoin("ugnot", 123)
coin3 := std.NewCoin("ugnot", -123)
return coin1.IsZero(), coin2.IsZero(), coin3.IsZero()
}

func IsPositive() (bool, bool, bool) {
coin1 := std.NewCoin("ugnot", -123)
coin2 := std.NewCoin("ugnot", 0)
coin3 := std.NewCoin("ugnot", 123)
return coin1.IsPositive(), coin2.IsPositive(), coin3.IsPositive()
}

func IsNegative() (bool, bool, bool) {
coin1 := std.NewCoin("ugnot", -123)
coin2 := std.NewCoin("ugnot", 0)
coin3 := std.NewCoin("ugnot", 123)
return coin1.IsNegative(), coin2.IsNegative(), coin3.IsNegative()
}

4 changes: 3 additions & 1 deletion gnovm/cmd/gno/transpile.go
Original file line number Diff line number Diff line change
Expand Up @@ -250,7 +250,9 @@ func transpileFile(srcPath string, opts *transpileOptions) error {
if !flags.skipImports {
importPaths := getPathsFromImportSpec(transpileRes.Imports)
for _, path := range importPaths {
transpilePkg(path, opts)
if err := transpilePkg(path, opts); err != nil {
return err
}
}
}

Expand Down
Loading

0 comments on commit 3ec2f72

Please sign in to comment.