/
keys.go
167 lines (139 loc) · 4.87 KB
/
keys.go
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
package ecocredit
import (
"fmt"
sdk "github.com/cosmos/cosmos-sdk/types"
"github.com/cosmos/cosmos-sdk/types/address"
sdkerrors "github.com/cosmos/cosmos-sdk/types/errors"
"github.com/regen-network/regen-ledger/types/math"
)
const (
// ModuleName is the module name constant used in many places
ModuleName = "ecocredit"
DefaultParamspace = ModuleName
TradableBalancePrefix byte = 0x0
TradableSupplyPrefix byte = 0x1
RetiredBalancePrefix byte = 0x2
RetiredSupplyPrefix byte = 0x3
CreditTypeSeqTablePrefix byte = 0x4
ClassInfoTablePrefix byte = 0x5
BatchInfoTablePrefix byte = 0x6
ORMPrefix byte = 0x7
)
// BatchDenomT is used to prevent errors when forming keys as accounts and denoms are
// both represented as strings
type BatchDenomT string
// - 0x0 <accAddrLen (1 Byte)><accAddr_Bytes><denom_Bytes>: TradableBalance
// - 0x1 <denom_Bytes>: TradableSupply
// - 0x2 <accAddrLen (1 Byte)><accAddr_Bytes><denom_Bytes>: RetiredBalance
// - 0x3 <denom_Bytes>: RetiredSupply
// TradableBalanceKey creates the index key for recipient address and batch-denom
func TradableBalanceKey(acc sdk.AccAddress, denom BatchDenomT) []byte {
key := []byte{TradableBalancePrefix}
key = append(key, address.MustLengthPrefix(acc)...)
return append(key, denom...)
}
// ParseBalanceKey parses the recipient address and batch-denom from tradable or retired balance key.
// Balance keys take the following form: <storage prefix 1 byte><addr length 1 byte><addr><batchDenom>
func ParseBalanceKey(key []byte) (sdk.AccAddress, BatchDenomT) {
addrLen := key[1]
addr := sdk.AccAddress(key[2 : 2+addrLen])
return addr, BatchDenomT(key[2+addrLen:])
}
// TradableSupplyKey creates the tradable supply key for a given batch-denom
func TradableSupplyKey(batchDenom BatchDenomT) []byte {
key := []byte{TradableSupplyPrefix}
return append(key, batchDenom...)
}
// ParseSupplyKey parses the batch-denom from tradable or retired supply key
func ParseSupplyKey(key []byte) BatchDenomT {
return BatchDenomT(key[1:])
}
// RetiredBalanceKey creates the index key for recipient address and batch-denom
func RetiredBalanceKey(acc sdk.AccAddress, batchDenom BatchDenomT) []byte {
key := []byte{RetiredBalancePrefix}
key = append(key, address.MustLengthPrefix(acc)...)
return append(key, batchDenom...)
}
// RetiredSupplyKey creates the retired supply key for a given batch-denom
func RetiredSupplyKey(batchDenom BatchDenomT) []byte {
key := []byte{RetiredSupplyPrefix}
return append(key, batchDenom...)
}
// GetDecimal retrieves a decimal by `key` from the given `store`
func GetDecimal(store sdk.KVStore, key []byte) (math.Dec, error) {
bz := store.Get(key)
if bz == nil {
return math.NewDecFromInt64(0), nil
}
value, err := math.NewDecFromString(string(bz))
if err != nil {
return math.Dec{}, sdkerrors.Wrap(err, fmt.Sprintf("can't unmarshal %s as decimal", bz))
}
return value, nil
}
// SetDecimal stores a decimal by `key` in the given `store`
func SetDecimal(store sdk.KVStore, key []byte, value math.Dec) {
// always remove all trailing zeros for canonical representation
value, _ = value.Reduce()
if value.IsZero() {
store.Delete(key)
} else {
// use floating notation here always for canonical representation
store.Set(key, []byte(value.String()))
}
}
// AddAndSetDecimal retrieves a decimal from the given key, adds it to x, and saves it.
func AddAndSetDecimal(store sdk.KVStore, key []byte, x math.Dec) error {
value, err := GetDecimal(store, key)
if err != nil {
return err
}
value, err = value.Add(x)
if err != nil {
return err
}
SetDecimal(store, key, value)
return nil
}
// SubAndSetDecimal retrieves a decimal from the given key, subtracts x from it, and saves it.
func SubAndSetDecimal(store sdk.KVStore, key []byte, x math.Dec) error {
value, err := GetDecimal(store, key)
if err != nil {
return err
}
if value.Cmp(x) == -1 {
return ErrInsufficientFunds
}
value, err = math.SafeSubBalance(value, x)
if err != nil {
return err
}
SetDecimal(store, key, value)
return nil
}
// IterateSupplies iterates over supplies and calls the specified callback function `cb`
func IterateSupplies(store sdk.KVStore, storeKey byte, cb func(denom, supply string) (bool, error)) error {
iter := sdk.KVStorePrefixIterator(store, []byte{storeKey})
defer iter.Close()
for ; iter.Valid(); iter.Next() {
stop, err := cb(string(ParseSupplyKey(iter.Key())), string(iter.Value()))
if err != nil {
return err
}
if stop {
break
}
}
return nil
}
// IterateBalances iterates over balances and calls the specified callback function `cb`
func IterateBalances(store sdk.KVStore, storeKey byte, cb func(address, denom, balance string) bool) {
iter := sdk.KVStorePrefixIterator(store, []byte{storeKey})
defer iter.Close()
for ; iter.Valid(); iter.Next() {
addr, denom := ParseBalanceKey(iter.Key())
if cb(addr.String(), string(denom), string(iter.Value())) {
break
}
}
}