-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathShard.cdc
315 lines (251 loc) · 10.1 KB
/
Shard.cdc
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
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
// import NonFungibleToken from 0x631e88ae7f1d7c20 // testnet
import NonFungibleToken from 0x1d7e57aa55817448 // mainnet
// eternal.gg
pub contract Shard: NonFungibleToken {
// Total amount of Shards that have been minted
pub var totalSupply: UInt64
// Total amount of Clips that have been created
pub var totalClips: UInt32
// Total amount of Moments that have been created
pub var totalMoments: UInt32
// Variable size dictionary of Moment structs
access(self) var moments: {UInt32: Moment}
// Variable size dictionary of Clip structs
access(self) var clips: {UInt32: Clip}
// Events
pub event ContractInitialized()
pub event Withdraw(id: UInt64, from: Address?)
pub event Deposit(id: UInt64, to: Address?)
pub event MomentCreated(id: UInt32, influencerID: String, splits: UInt8, metadata: {String: String})
pub event ClipCreated(id: UInt32, momentID: UInt32, sequence: UInt8, metadata: {String: String})
pub event ShardMinted(id: UInt64, clipID: UInt32)
pub struct Moment {
// The unique ID of the Moment
pub let id: UInt32
// The influencer that the Moment belongs to
pub let influencerID: String
// The amount of Clips the Moments splits into
pub let splits: UInt8
// The metadata for a Moment
access(contract) let metadata: {String: String}
init(influencerID: String, splits: UInt8, metadata: {String: String}) {
pre {
metadata.length > 0: "Metadata cannot be empty"
}
self.id = Shard.totalMoments
self.influencerID = influencerID
self.splits = splits
self.metadata = metadata
// Increment the ID so that it isn't used again
Shard.totalMoments = Shard.totalMoments + (1 as UInt32)
// Broadcast the new Moment's data
emit MomentCreated(
id: self.id,
influencerID: self.influencerID,
splits: self.splits,
metadata: self.metadata
)
}
}
pub struct Clip {
// The unique ID of the Clip
pub let id: UInt32
// The moment the Clip belongs to
pub let momentID: UInt32
// The sequence of the provided clip
pub let sequence: UInt8
// Stores all the metadata about the Clip as a string mapping
access(contract) let metadata: {String: String}
init(momentID: UInt32, sequence: UInt8, metadata: {String: String}) {
pre {
Shard.moments.containsKey(momentID): "Provided Moment ID does not exist"
Shard.moments[momentID]!.splits > sequence: "The Sequence must be within the Moment's splits limit"
metadata.length > 0: "Metadata cannot be empty"
}
self.id = Shard.totalClips
self.momentID = momentID
self.sequence = sequence
self.metadata = metadata
// Increment the ID so that it isn't used again
Shard.totalClips = Shard.totalClips + (1 as UInt32)
// Broadcast the new Clip's data
emit ClipCreated(
id: self.id,
momentID: self.momentID,
sequence: self.sequence,
metadata: self.metadata
)
}
}
// Add your own Collection interface so you can use it later
pub resource interface ShardCollectionPublic {
pub fun deposit(token: @NonFungibleToken.NFT)
pub fun getIDs(): [UInt64]
pub fun borrowNFT(id: UInt64): &NonFungibleToken.NFT
pub fun borrowShardNFT(id: UInt64): &Shard.NFT? {
post {
(result == nil) || (result?.id == id):
"Cannot borrow Shard reference: The ID of the returned reference is incorrect"
}
}
}
pub resource NFT: NonFungibleToken.INFT {
// Identifier of NFT
pub let id: UInt64
// Clip ID corresponding to the Shard
pub let clipID: UInt32
init(initID: UInt64, clipID: UInt32) {
pre {
Shard.clips.containsKey(clipID): "Clip ID does not exist"
}
self.id = initID
self.clipID = clipID
// Increase the total supply counter
Shard.totalSupply = Shard.totalSupply + (1 as UInt64)
emit ShardMinted(id: self.id, clipID: self.clipID)
}
}
pub resource Collection: ShardCollectionPublic, NonFungibleToken.Provider, NonFungibleToken.Receiver, NonFungibleToken.CollectionPublic {
// A resource type with an `UInt64` ID field
pub var ownedNFTs: @{UInt64: NonFungibleToken.NFT}
init () {
self.ownedNFTs <- {}
}
// Removes an NFT from the collection and moves it to the caller
pub fun withdraw(withdrawID: UInt64): @NonFungibleToken.NFT {
let token <- self.ownedNFTs.remove(key: withdrawID) ?? panic("missing NFT")
emit Withdraw(id: token.id, from: self.owner?.address)
return <-token
}
// Takes a NFT and adds it to the collections dictionary and adds the ID to the id array
pub fun deposit(token: @NonFungibleToken.NFT) {
let token <- token as! @Shard.NFT
let id: UInt64 = token.id
// Add the new token to the dictionary which removes the old one
let oldToken <- self.ownedNFTs[id] <- token
emit Deposit(id: id, to: self.owner?.address)
destroy oldToken
}
// Returns an array of the IDs that are in the collection
pub fun getIDs(): [UInt64] {
return self.ownedNFTs.keys
}
// Gets a reference to an NFT in the collection
// so that the caller can read its metadata and call its methods
pub fun borrowNFT(id: UInt64): &NonFungibleToken.NFT {
return (&self.ownedNFTs[id] as &NonFungibleToken.NFT?)!
}
// Gets a reference to the Shard NFT for metadata and such
pub fun borrowShardNFT(id: UInt64): &Shard.NFT? {
if self.ownedNFTs[id] != nil {
let ref = (&self.ownedNFTs[id] as auth &NonFungibleToken.NFT?)!
return ref as! &Shard.NFT
} else {
return nil
}
}
destroy() {
destroy self.ownedNFTs
}
}
// A special authorization resource with administrative functions
pub resource Admin {
// Creates a new Moment and returns the ID
pub fun createMoment(influencerID: String, splits: UInt8, metadata: {String: String}): UInt32 {
var newMoment = Moment(influencerID: influencerID, splits: splits, metadata: metadata)
let newID = newMoment.id
// Store it in the contract storage
Shard.moments[newID] = newMoment
return newID
}
// Creates a new Clip struct and returns the ID
pub fun createClip(
momentID: UInt32,
sequence: UInt8,
metadata: {String: String}
): UInt32 {
// Create the new Clip
var newClip = Clip(
momentID: momentID,
sequence: sequence,
metadata: metadata
)
var newID = newClip.id
// Store it in the contract storage
Shard.clips[newID] = newClip
return newID
}
// Mints a new NFT with a new ID
pub fun mintNFT(
recipient: &{Shard.ShardCollectionPublic},
clipID: UInt32
) {
// Creates a new NFT with provided arguments
var newNFT <- create NFT(
initID: Shard.totalSupply,
clipID: clipID
)
// Deposits it in the recipient's account using their reference
recipient.deposit(token: <-newNFT)
}
pub fun batchMintNFT(
recipient: &{Shard.ShardCollectionPublic},
clipID: UInt32,
quantity: UInt64
) {
var i: UInt64 = 0
while i < quantity {
self.mintNFT(recipient: recipient, clipID: clipID)
i = i + (1 as UInt64)
}
}
// Creates a new Admin resource to be given to an account
pub fun createNewAdmin(): @Admin {
return <-create Admin()
}
}
// Public function that anyone can call to create a new empty collection
pub fun createEmptyCollection(): @Shard.Collection {
return <- create Collection()
}
// Publicly get a Moment for a given Moment ID
pub fun getMoment(momentID: UInt32): Moment? {
return self.moments[momentID]
}
// Publicly get a Clip for a given Clip ID
pub fun getClip(clipID: UInt32): Clip? {
return self.clips[clipID]
}
// Publicly get metadata for a given Moment ID
pub fun getMomentMetadata(momentID: UInt32): {String: String}? {
return self.moments[momentID]?.metadata
}
// Publicly get metadata for a given Clip ID
pub fun getClipMetadata(clipID: UInt32): {String: String}? {
return self.clips[clipID]?.metadata
}
// Publicly get all Clips
pub fun getAllClips(): [Shard.Clip] {
return Shard.clips.values
}
init() {
// Initialize the total supplies
self.totalSupply = 0
self.totalMoments = 0
self.totalClips = 0
// Initialize with an empty set of Moments
self.moments = {}
// Initialize with an empty set of Clips
self.clips = {}
// Create a Collection resource and save it to storage
self.account.save(<-create Collection(), to: /storage/EternalShardCollection)
// Create an Admin resource and save it to storage
self.account.save(<- create Admin(), to: /storage/EternalShardAdmin)
// Create a public capability for the collection
self.account.link<&{Shard.ShardCollectionPublic}>(
/public/EternalShardCollection,
target: /storage/EternalShardCollection
)
emit ContractInitialized()
}
}