This repository has been archived by the owner on Nov 28, 2023. It is now read-only.
/
collection.go
215 lines (178 loc) · 5.89 KB
/
collection.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
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
package types
import (
"encoding/json"
"fmt"
"sort"
"strings"
sdk "github.com/cosmos/cosmos-sdk/types"
"github.com/cosmos/modules/incubator/nft/exported"
)
// Collection of non fungible tokens
type Collection struct {
Denom string `json:"denom,omitempty" yaml:"denom"` // name of the collection; not exported to clients
NFTs NFTs `json:"nfts" yaml:"nfts"` // NFTs that belong to a collection
}
// NewCollection creates a new NFT Collection
func NewCollection(denom string, nfts NFTs) Collection {
return Collection{
Denom: strings.TrimSpace(denom),
NFTs: nfts,
}
}
// EmptyCollection returns an empty collection
func EmptyCollection() Collection {
return NewCollection("", NewNFTs())
}
// GetNFT gets a NFT from the collection
func (collection Collection) GetNFT(id string) (nft exported.NFT, err sdk.Error) {
nft, found := collection.NFTs.Find(id)
if found {
return nft, nil
}
return nil, ErrUnknownNFT(DefaultCodespace,
fmt.Sprintf("NFT #%s doesn't exist in collection %s", id, collection.Denom),
)
}
// ContainsNFT returns whether or not a Collection contains an NFT
func (collection Collection) ContainsNFT(id string) bool {
_, err := collection.GetNFT(id)
return err == nil
}
// AddNFT adds an NFT to the collection
func (collection Collection) AddNFT(nft exported.NFT) (Collection, sdk.Error) {
id := nft.GetID()
exists := collection.ContainsNFT(id)
if exists {
return collection, ErrNFTAlreadyExists(DefaultCodespace,
fmt.Sprintf("NFT #%s already exists in collection %s", id, collection.Denom),
)
}
collection.NFTs = collection.NFTs.Append(nft)
return collection, nil
}
// UpdateNFT updates an NFT from a collection
func (collection Collection) UpdateNFT(nft exported.NFT) (Collection, sdk.Error) {
nfts, ok := collection.NFTs.Update(nft.GetID(), nft)
if !ok {
return collection, ErrUnknownNFT(DefaultCodespace,
fmt.Sprintf("NFT #%s doesn't exist on collection %s", nft.GetID(), collection.Denom),
)
}
collection.NFTs = nfts
return collection, nil
}
// DeleteNFT deletes an NFT from a collection
func (collection Collection) DeleteNFT(nft exported.NFT) (Collection, sdk.Error) {
nfts, ok := collection.NFTs.Remove(nft.GetID())
if !ok {
return collection, ErrUnknownNFT(DefaultCodespace,
fmt.Sprintf("NFT #%s doesn't exist on collection %s", nft.GetID(), collection.Denom),
)
}
collection.NFTs = nfts
return collection, nil
}
// Supply gets the total supply of NFTs of a collection
func (collection Collection) Supply() int {
return len(collection.NFTs)
}
// String follows stringer interface
func (collection Collection) String() string {
return fmt.Sprintf(`Denom: %s
NFTs:
%s`,
collection.Denom,
collection.NFTs.String(),
)
}
// ----------------------------------------------------------------------------
// Collections
// Collections define an array of Collection
type Collections []Collection
// NewCollections creates a new set of NFTs
func NewCollections(collections ...Collection) Collections {
if len(collections) == 0 {
return Collections{}
}
return Collections(collections).Sort()
}
// Append appends two sets of Collections
func (collections Collections) Append(collectionsB ...Collection) Collections {
return append(collections, collectionsB...).Sort()
}
// Find returns the searched collection from the set
func (collections Collections) Find(denom string) (Collection, bool) {
index := collections.find(denom)
if index == -1 {
return Collection{}, false
}
return collections[index], true
}
// Remove removes a collection from the set of collections
func (collections Collections) Remove(denom string) (Collections, bool) {
index := collections.find(denom)
if index == -1 {
return collections, false
}
collections[len(collections)-1], collections[index] = collections[index], collections[len(collections)-1]
return collections[:len(collections)-1], true
}
// String follows stringer interface
func (collections Collections) String() string {
if len(collections) == 0 {
return ""
}
out := ""
for _, collection := range collections {
out += fmt.Sprintf("%v\n", collection.String())
}
return out[:len(out)-1]
}
// Empty returns true if there are no collections and false otherwise.
func (collections Collections) Empty() bool {
return len(collections) == 0
}
func (collections Collections) find(denom string) (idx int) {
return FindUtil(collections, denom)
}
// ----------------------------------------------------------------------------
// Encoding
// CollectionJSON is the exported Collection format for clients
type CollectionJSON map[string]Collection
// MarshalJSON for Collections
func (collections Collections) MarshalJSON() ([]byte, error) {
collectionJSON := make(CollectionJSON)
for _, collection := range collections {
denom := collection.Denom
collection.Denom = ""
collectionJSON[denom] = collection
}
return json.Marshal(collectionJSON)
}
// UnmarshalJSON for Collections
func (collections *Collections) UnmarshalJSON(b []byte) error {
collectionJSON := make(CollectionJSON)
if err := json.Unmarshal(b, &collectionJSON); err != nil {
return err
}
for denom, collection := range collectionJSON {
*collections = append(*collections, NewCollection(denom, collection.NFTs))
}
return nil
}
//-----------------------------------------------------------------------------
// Sort & Findable interfaces
func (collections Collections) ElAtIndex(index int) string { return collections[index].Denom }
func (collections Collections) Len() int { return len(collections) }
func (collections Collections) Less(i, j int) bool {
return strings.Compare(collections[i].Denom, collections[j].Denom) == -1
}
func (collections Collections) Swap(i, j int) {
collections[i], collections[j] = collections[j], collections[i]
}
var _ sort.Interface = Collections{}
// Sort is a helper function to sort the set of coins inplace
func (collections Collections) Sort() Collections {
sort.Sort(collections)
return collections
}