cosmos-sdk/types/coin.go

208 lines
4.4 KiB
Go
Raw Normal View History

2017-12-25 00:57:07 -08:00
package types
2016-04-01 15:19:07 -07:00
import (
"fmt"
"sort"
2016-04-01 15:19:07 -07:00
"strings"
)
2017-07-06 05:59:45 -07:00
// Coin hold some amount of one currency
2016-04-01 15:19:07 -07:00
type Coin struct {
Denom string `json:"denom"`
Amount int64 `json:"amount"`
}
2017-07-12 09:54:07 -07:00
// String provides a human-readable representation of a coin
2016-04-01 15:19:07 -07:00
func (coin Coin) String() string {
2017-03-28 13:32:55 -07:00
return fmt.Sprintf("%v%v", coin.Amount, coin.Denom)
}
2017-07-12 09:54:07 -07:00
// IsZero returns if this represents no money
func (coin Coin) IsZero() bool {
return coin.Amount == 0
}
// IsGTE returns true if they are the same type and the receiver is
// an equal or greater value
func (coin Coin) IsGTE(other Coin) bool {
return (coin.Denom == other.Denom) &&
(coin.Amount >= other.Amount)
}
2016-04-01 15:19:07 -07:00
//----------------------------------------
2017-12-21 03:26:40 -08:00
// Coins
2016-04-01 15:19:07 -07:00
2017-07-06 05:59:45 -07:00
// Coins is a set of Coin, one per currency
2016-04-01 15:19:07 -07:00
type Coins []Coin
func (coins Coins) String() string {
if len(coins) == 0 {
return ""
}
out := ""
for _, coin := range coins {
2017-03-28 13:32:55 -07:00
out += fmt.Sprintf("%v,", coin.String())
}
2017-04-13 18:33:39 -07:00
return out[:len(out)-1]
}
2017-07-06 05:59:45 -07:00
// IsValid asserts the Coins are sorted, and don't have 0 amounts
2016-04-01 15:19:07 -07:00
func (coins Coins) IsValid() bool {
switch len(coins) {
case 0:
return true
case 1:
return coins[0].Amount != 0
default:
lowDenom := coins[0].Denom
for _, coin := range coins[1:] {
if coin.Denom <= lowDenom {
return false
}
if coin.Amount == 0 {
return false
}
2017-01-31 03:24:49 -08:00
// we compare each coin against the last denom
lowDenom = coin.Denom
2016-04-01 15:19:07 -07:00
}
return true
}
}
2017-07-06 05:59:45 -07:00
// Plus combines to sets of coins
//
2017-02-24 14:12:05 -08:00
// TODO: handle empty coins!
// Currently appends an empty coin ...
2017-07-06 20:37:45 -07:00
func (coins Coins) Plus(coinsB Coins) Coins {
2016-04-01 15:19:07 -07:00
sum := []Coin{}
indexA, indexB := 0, 0
2017-07-06 20:37:45 -07:00
lenA, lenB := len(coins), len(coinsB)
2016-04-01 15:19:07 -07:00
for {
if indexA == lenA {
if indexB == lenB {
return sum
}
2017-07-06 05:59:45 -07:00
return append(sum, coinsB[indexB:]...)
2016-04-01 15:19:07 -07:00
} else if indexB == lenB {
2017-07-06 20:37:45 -07:00
return append(sum, coins[indexA:]...)
2016-04-01 15:19:07 -07:00
}
2017-07-06 20:37:45 -07:00
coinA, coinB := coins[indexA], coinsB[indexB]
2016-04-01 15:19:07 -07:00
switch strings.Compare(coinA.Denom, coinB.Denom) {
case -1:
sum = append(sum, coinA)
2017-07-06 05:59:45 -07:00
indexA++
2016-04-01 15:19:07 -07:00
case 0:
if coinA.Amount+coinB.Amount == 0 {
// ignore 0 sum coin type
} else {
sum = append(sum, Coin{
Denom: coinA.Denom,
Amount: coinA.Amount + coinB.Amount,
})
}
2017-07-06 05:59:45 -07:00
indexA++
indexB++
2016-04-01 15:19:07 -07:00
case 1:
sum = append(sum, coinB)
2017-07-06 05:59:45 -07:00
indexB++
2016-04-01 15:19:07 -07:00
}
}
return sum
}
2017-07-06 05:59:45 -07:00
// Negative returns a set of coins with all amount negative
2016-04-01 15:19:07 -07:00
func (coins Coins) Negative() Coins {
res := make([]Coin, 0, len(coins))
for _, coin := range coins {
res = append(res, Coin{
Denom: coin.Denom,
Amount: -coin.Amount,
})
}
return res
}
2017-07-06 05:59:45 -07:00
// Minus subtracts a set of coins from another (adds the inverse)
2017-07-06 20:37:45 -07:00
func (coins Coins) Minus(coinsB Coins) Coins {
return coins.Plus(coinsB.Negative())
2016-04-01 15:19:07 -07:00
}
2017-07-06 20:37:45 -07:00
// IsGTE returns True iff coins is NonNegative(), and for every
2017-07-06 05:59:45 -07:00
// currency in coinsB, the currency is present at an equal or greater
// amount in coinsB
2017-07-06 20:37:45 -07:00
func (coins Coins) IsGTE(coinsB Coins) bool {
diff := coins.Minus(coinsB)
2016-04-01 15:19:07 -07:00
if len(diff) == 0 {
return true
}
2018-01-03 17:20:21 -08:00
return diff.IsNotNegative()
2016-04-01 15:19:07 -07:00
}
2017-07-06 05:59:45 -07:00
// IsZero returns true if there are no coins
2016-04-01 15:19:07 -07:00
func (coins Coins) IsZero() bool {
return len(coins) == 0
}
2017-07-06 05:59:45 -07:00
// IsEqual returns true if the two sets of Coins have the same value
2017-07-06 20:37:45 -07:00
func (coins Coins) IsEqual(coinsB Coins) bool {
if len(coins) != len(coinsB) {
2016-04-01 15:19:07 -07:00
return false
}
2017-07-06 20:37:45 -07:00
for i := 0; i < len(coins); i++ {
if coins[i] != coinsB[i] {
2016-04-01 15:19:07 -07:00
return false
}
}
return true
}
2017-07-06 05:59:45 -07:00
// IsPositive returns true if there is at least one coin, and all
// currencies have a positive value
2016-04-01 15:19:07 -07:00
func (coins Coins) IsPositive() bool {
if len(coins) == 0 {
return false
}
for _, coinAmount := range coins {
if coinAmount.Amount <= 0 {
return false
}
}
return true
}
2018-01-03 17:20:21 -08:00
// IsNotNegative returns true if there is no currency with a negative value
2017-07-06 05:59:45 -07:00
// (even no coins is true here)
2018-01-03 17:20:21 -08:00
func (coins Coins) IsNotNegative() bool {
if len(coins) == 0 {
return true
}
for _, coinAmount := range coins {
if coinAmount.Amount < 0 {
return false
}
}
return true
}
2017-12-21 03:26:40 -08:00
//----------------------------------------
// Sort interface
2017-07-06 05:59:45 -07:00
//nolint
func (coins Coins) Len() int { return len(coins) }
func (coins Coins) Less(i, j int) bool { return coins[i].Denom < coins[j].Denom }
func (coins Coins) Swap(i, j int) { coins[i], coins[j] = coins[j], coins[i] }
var _ sort.Interface = Coins{}
// Sort is a helper function to sort the set of coins inplace
func (coins Coins) Sort() { sort.Sort(coins) }
2017-12-25 00:57:07 -08:00
//----------------------------------------
// Misc
type Coinser interface {
GetCoins() Coins
SetCoins(Coins)
}