-
Notifications
You must be signed in to change notification settings - Fork 373
/
coins.gno
190 lines (154 loc) · 4.36 KB
/
coins.gno
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
package std
import (
"math/overflow"
"strconv"
)
// NOTE: this is selectively copied over from tm2/pkgs/std/coin.go
// Coin holds some amount of one currency.
// A negative amount is invalid.
type Coin struct {
Denom string `json:"denom"`
Amount int64 `json:"amount"`
}
// NewCoin returns a new coin with a denomination and amount
func NewCoin(denom string, amount int64) Coin {
return Coin{
Denom: denom,
Amount: amount,
}
}
// String provides a human-readable representation of a coin
func (c Coin) String() string {
return strconv.Itoa(int(c.Amount)) + c.Denom
}
// IsGTE returns true if they are the same type and the receiver is
// an equal or greater value
func (c Coin) IsGTE(other Coin) bool {
mustMatchDenominations(c.Denom, other.Denom)
return c.Amount >= other.Amount
}
// IsLT returns true if they are the same type and the receiver is
// a smaller value
func (c Coin) IsLT(other Coin) bool {
mustMatchDenominations(c.Denom, other.Denom)
return c.Amount < other.Amount
}
// IsEqual returns true if the two sets of Coins have the same value
func (c Coin) IsEqual(other Coin) bool {
mustMatchDenominations(c.Denom, other.Denom)
return c.Amount == other.Amount
}
// Add adds amounts of two coins with same denom.
// If the coins differ in denom then it panics.
// An overflow or underflow panics.
// An invalid result panics.
func (c Coin) Add(other Coin) Coin {
mustMatchDenominations(c.Denom, other.Denom)
sum, ok := overflow.Add64(c.Amount, other.Amount)
if !ok {
panic("coin add overflow/underflow: " + strconv.Itoa(int(c.Amount)) + " +/- " + strconv.Itoa(int(other.Amount)))
}
c.Amount = sum
return c
}
// Sub subtracts amounts of two coins with same denom.
// If the coins differ in denom then it panics.
// An overflow or underflow panics.
// An invalid result panics.
func (c Coin) Sub(other Coin) Coin {
mustMatchDenominations(c.Denom, other.Denom)
dff, ok := overflow.Sub64(c.Amount, other.Amount)
if !ok {
panic("coin sub overflow/underflow: " + strconv.Itoa(int(c.Amount)) + " +/- " + strconv.Itoa(int(other.Amount)))
}
c.Amount = dff
return c
}
// IsPositive returns true if coin amount is positive.
func (c Coin) IsPositive() bool {
return c.Amount > 0
}
// IsNegative returns true if the coin amount is negative and false otherwise.
func (c Coin) IsNegative() bool {
return c.Amount < 0
}
// IsZero returns true if the amount of given coin is zero
func (c Coin) IsZero() bool {
return c.Amount == 0
}
func mustMatchDenominations(denomA, denomB string) {
if denomA != denomB {
panic("incompatible coin denominations: " + denomA + ", " + denomB)
}
}
// Coins is a set of Coin, one per currency
type Coins []Coin
// NewCoins returns a new set of Coins given one or more Coins
// Consolidates any denom duplicates into one, keeping the properties of a mathematical set
func NewCoins(coins ...Coin) Coins {
coinMap := make(map[string]int64)
for _, coin := range coins {
if currentAmount, exists := coinMap[coin.Denom]; exists {
var ok bool
if coinMap[coin.Denom], ok = overflow.Add64(currentAmount, coin.Amount); !ok {
panic("coin sub overflow/underflow: " + strconv.Itoa(int(currentAmount)) + " +/- " + strconv.Itoa(int(coin.Amount)))
}
} else {
coinMap[coin.Denom] = coin.Amount
}
}
var setCoins Coins
for denom, amount := range coinMap {
setCoins = append(setCoins, NewCoin(denom, amount))
}
return setCoins
}
// String returns the string representation of Coins
func (cz Coins) String() string {
if len(cz) == 0 {
return ""
}
res := ""
for i, c := range cz {
if i > 0 {
res += ","
}
res += c.String()
}
return res
}
// AmountOf returns the amount of a specific coin from the Coins set
func (cz Coins) AmountOf(denom string) int64 {
for _, c := range cz {
if c.Denom == denom {
return c.Amount
}
}
return 0
}
// Add adds a Coin to the Coins set
func (cz Coins) Add(b Coins) Coins {
c := Coins{}
for _, ac := range cz {
bc := b.AmountOf(ac.Denom)
ac.Amount += bc
c = append(c, ac)
}
for _, bc := range b {
cc := c.AmountOf(bc.Denom)
if cc == 0 {
c = append(c, bc)
}
}
return c
}
// expandNative expands for usage within natively bound functions.
func (cz Coins) expandNative() (denoms []string, amounts []int64) {
denoms = make([]string, len(cz))
amounts = make([]int64, len(cz))
for i, coin := range cz {
denoms[i] = coin.Denom
amounts[i] = coin.Amount
}
return denoms, amounts
}