Smart Contract
SGKCLDR_bk_2bs_mf
A.ef87d569e9562678.SGKCLDR_bk_2bs_mf
1// SPDX-License-Identifier: UNLICENSED
2//
3//
4import NonFungibleToken from 0x1d7e57aa55817448
5import Anique from 0xe2e1689b53e92a82
6
7pub contract SGKCLDR_bk_2bs_mf: NonFungibleToken, Anique {
8 // -----------------------------------------------------------------------
9 // SGKCLDR_bk_2bs_mf contract Events
10 // -----------------------------------------------------------------------
11
12 // Events for Contract-Related actions
13 //
14 // Emitted when the SGKCLDR_bk_2bs_mf contract is created
15 pub event ContractInitialized()
16
17 // Events for Item-Related actions
18 //
19 // Emitted when a new Item struct is created
20 pub event ItemCreated(id: UInt32, metadata: {String:String})
21
22 // Events for Collectible-Related actions
23 //
24 // Emitted when an CollectibleData NFT is minted
25 pub event CollectibleMinted(collectibleID: UInt64, itemID: UInt32, serialNumber: UInt32)
26 // Emitted when an CollectibleData NFT is destroyed
27 pub event CollectibleDestroyed(collectibleID: UInt64)
28
29 // events for Collection-related actions
30 //
31 // Emitted when an CollectibleData is withdrawn from a Collection
32 pub event Withdraw(id: UInt64, from: Address?)
33 // Emitted when an CollectibleData is deposited into a Collection
34 pub event Deposit(id: UInt64, to: Address?)
35
36 // paths
37 pub let collectionStoragePath: StoragePath
38 pub let collectionPublicPath: PublicPath
39 pub let collectionPrivatePath: PrivatePath
40 pub let adminStoragePath: StoragePath
41 pub let saleCollectionStoragePath: StoragePath
42 pub let saleCollectionPublicPath: PublicPath
43
44 // -----------------------------------------------------------------------
45 // SGKCLDR_bk_2bs_mf contract-level fields.
46 // These contain actual values that are stored in the smart contract.
47 // -----------------------------------------------------------------------
48
49 // fields for Item-related
50 //
51 // variable size dictionary of Item resources
52 access(self) var items: @{UInt32: Item}
53
54 // The ID that is used to create Items.
55 pub var nextItemID: UInt32
56
57 // fields for Collectible-related
58 //
59 // Total number of CollectibleData NFTs that have been minted ever.
60 pub var totalSupply: UInt64
61
62 // -----------------------------------------------------------------------
63 // SGKCLDR_bk_2bs_mf contract-level Composite Type definitions
64 // -----------------------------------------------------------------------
65
66 // The structure that represents Item
67 // each digital content which SGKCLDR_bk_2bs_mf deal with on Flow
68 //
69 pub struct ItemData {
70
71 pub let itemID: UInt32
72
73 pub let metadata: {String: String}
74
75 init(itemID: UInt32) {
76 let item = (&SGKCLDR_bk_2bs_mf.items[itemID] as &Item?)!
77
78 self.itemID = item.itemID
79 self.metadata = item.metadata
80 }
81 }
82
83 // Item is a resource type that contains the functions to mint Collectibles.
84 //
85 // It is stored in a private field in the contract so that
86 // the admin resource can call its methods and that there can be
87 // public getters for some of its fields
88 //
89 // The admin can mint Collectibles that refer from Item.
90 pub resource Item {
91
92 // unique ID for the Item
93 pub let itemID: UInt32
94
95 // Stores all the metadata about the item as a string mapping
96 // This is not the long term way NFT metadata will be stored. It's a temporary
97 // construct while we figure out a better way to do metadata.
98 //
99 pub let metadata: {String: String}
100
101 // The number of Collectibles that have been minted per Item.
102 access(contract) var numberMintedPerItem: UInt32
103
104 init(metadata: {String: String}) {
105 pre {
106 metadata.length != 0: "New Item metadata cannot be empty"
107 }
108 self.itemID = SGKCLDR_bk_2bs_mf.nextItemID
109 self.metadata = metadata
110 self.numberMintedPerItem = 0
111
112 // increment the nextItemID so that it isn't used again
113 SGKCLDR_bk_2bs_mf.nextItemID = SGKCLDR_bk_2bs_mf.nextItemID + 1
114
115 emit ItemCreated(id: self.itemID, metadata: metadata)
116 }
117
118 // mintCollectible mints a new Collectible and returns the newly minted Collectible
119 //
120 // Returns: The NFT that was minted
121 //
122 pub fun mintCollectible(): @NFT {
123 // get the number of Collectibles that have been minted for this Item
124 // to use as this Collectible's serial number
125 let numInItem = self.numberMintedPerItem
126
127 // mint the new Collectible
128 let newCollectible: @NFT <- create NFT(serialNumber: numInItem + 1,
129 itemID: self.itemID)
130
131 // Increment the count of Collectibles minted for this Item
132 self.numberMintedPerItem = numInItem + 1
133
134 return <-newCollectible
135 }
136
137 // batchMintCollectible mints an arbitrary quantity of Collectibles
138 // and returns them as a Collection
139 //
140 // Parameters: itemID: the ID of the Item that the Collectibles are minted for
141 // quantity: The quantity of Collectibles to be minted
142 //
143 // Returns: Collection object that contains all the Collectibles that were minted
144 //
145 pub fun batchMintCollectible(quantity: UInt64): @Collection {
146 let newCollection <- create Collection()
147
148 var i: UInt64 = 0
149 while i < quantity {
150 newCollection.deposit(token: <-self.mintCollectible())
151 i = i + 1
152 }
153
154 return <-newCollection
155 }
156
157 // Returns: the number of Collectibles
158 pub fun getNumberMinted(): UInt32 {
159 return self.numberMintedPerItem
160 }
161 }
162
163 // The structure holds metadata of an Collectible
164 pub struct CollectibleData {
165 // The ID of the Item that the Collectible references
166 pub let itemID: UInt32
167
168 // The place in the Item that this Collectible was minted
169 pub let serialNumber: UInt32
170
171 init(itemID: UInt32, serialNumber: UInt32) {
172 self.itemID = itemID
173 self.serialNumber = serialNumber
174 }
175 }
176
177 // The resource that represents the CollectibleData NFTs
178 //
179 pub resource NFT: NonFungibleToken.INFT, Anique.INFT {
180
181 // Global unique collectibleData ID
182 pub let id: UInt64
183
184 // Struct of Collectible metadata
185 pub let data: CollectibleData
186
187 init(serialNumber: UInt32, itemID: UInt32) {
188 // Increment the global Collectible IDs
189 SGKCLDR_bk_2bs_mf.totalSupply = SGKCLDR_bk_2bs_mf.totalSupply + 1
190
191 // set id
192 self.id = SGKCLDR_bk_2bs_mf.totalSupply
193
194 // Set the metadata struct
195 self.data = CollectibleData(itemID: itemID, serialNumber: serialNumber)
196
197 emit CollectibleMinted(collectibleID: self.id, itemID: itemID, serialNumber: self.data.serialNumber)
198 }
199
200 destroy() {
201 emit CollectibleDestroyed(collectibleID: self.id)
202 }
203 }
204
205 // interface that represents SGKCLDR_bk_2bs_mf collections to public
206 // extends of NonFungibleToken.CollectionPublic
207 pub resource interface CollectionPublic {
208
209 pub fun deposit(token: @NonFungibleToken.NFT)
210 pub fun getIDs(): [UInt64]
211 pub fun borrowNFT(id: UInt64): &NonFungibleToken.NFT
212
213 // deposit multi tokens
214 pub fun batchDeposit(tokens: @Anique.Collection)
215
216 // contains NFT
217 pub fun contains(id: UInt64): Bool
218
219 // borrow NFT as SGKCLDR_bk_2bs_mf token
220 pub fun borrowSGKCLDR_bk_2bs_mfCollectible(id: UInt64): auth &NFT
221 }
222
223 // Collection is a resource that every user who owns NFTs
224 // will store in their account to manage their NFTs
225 //
226 pub resource Collection: CollectionPublic, NonFungibleToken.Receiver, NonFungibleToken.Provider, NonFungibleToken.CollectionPublic {
227 // Dictionary of CollectibleData conforming tokens
228 // NFT is a resource type with a UInt64 ID field
229 pub var ownedNFTs: @{UInt64: NonFungibleToken.NFT}
230
231 init() {
232 self.ownedNFTs <- {}
233 }
234
235 // withdraw removes a Collectible from the Collection and moves it to the caller
236 //
237 // Parameters: withdrawID: The ID of the NFT
238 // that is to be removed from the Collection
239 //
240 // returns: @NonFungibleToken.NFT the token that was withdrawn
241 pub fun withdraw(withdrawID: UInt64): @NonFungibleToken.NFT {
242
243 // Remove the nft from the Collection
244 let token <- self.ownedNFTs.remove(key: withdrawID)
245 ?? panic("Cannot withdraw: Collectible does not exist in the collection")
246
247 emit Withdraw(id: token.id, from: self.owner?.address)
248
249 // Return the withdrawn token
250 return <- token
251 }
252
253 // batchWithdraw withdraws multiple tokens and returns them as a Collection
254 //
255 // Parameters: collectibleIds: An array of IDs to withdraw
256 //
257 // Returns: @NonFungibleToken.Collection: A collection that contains
258 // the withdrawn collectibles
259 //
260 pub fun batchWithdraw(collectibleIds: [UInt64]): @Anique.Collection {
261 // Create a new empty Collection
262 var batchCollection <- create Collection()
263
264 // Iterate through the collectibleIds and withdraw them from the Collection
265 for collectibleID in collectibleIds {
266 batchCollection.deposit(token: <-self.withdraw(withdrawID: collectibleID))
267 }
268
269 // Return the withdrawn tokens
270 return <-batchCollection
271 }
272
273 // deposit takes a Collectible and adds it to the Collections dictionary
274 //
275 // Parameters: token: the NFT to be deposited in the collection
276 //
277 pub fun deposit(token: @NonFungibleToken.NFT) {
278
279 // Cast the deposited token as an SGKCLDR_bk_2bs_mf NFT to make sure
280 // it is the correct type
281 let token <- token as! @SGKCLDR_bk_2bs_mf.NFT
282
283 // Get the token's ID
284 let id = token.id
285
286 // Add the new token to the dictionary
287 let oldToken <- self.ownedNFTs[id] <- token
288
289 // Only emit a deposit event if the Collection
290 // is in an account's storage
291 if self.owner?.address != nil {
292 emit Deposit(id: id, to: self.owner?.address)
293 }
294
295 // Destroy the empty old token that was "removed"
296 destroy oldToken
297 }
298
299 // batchDeposit takes a Collection object as an argument
300 // and deposits each contained NFT into this Collection
301 pub fun batchDeposit(tokens: @Anique.Collection) {
302
303 // Get an array of the IDs to be deposited
304 let keys = tokens.getIDs()
305
306 // Iterate through the keys in the collection and deposit each one
307 for key in keys {
308 self.deposit(token: <-tokens.withdraw(withdrawID: key))
309 }
310
311 // Destroy the empty Collection
312 destroy tokens
313 }
314
315 // getIDs returns an array of the IDs that are in the Collection
316 pub fun getIDs(): [UInt64] {
317 return self.ownedNFTs.keys
318 }
319
320 // contains returns whether ID is in the Collection
321 pub fun contains(id: UInt64): Bool {
322 return self.ownedNFTs[id] != nil
323 }
324
325 // borrowNFT Returns a borrowed reference to a Collectible in the Collection
326 // so that the caller can read its ID
327 //
328 // Parameters: id: The ID of the NFT to get the reference for
329 //
330 // Returns: A reference to the NFT
331 //
332 // Note: This only allows the caller to read the ID of the NFT,
333 // not any SGKCLDR_bk_2bs_mf specific data. Please use borrowCollectible to
334 // read Collectible data.
335 //
336 pub fun borrowNFT(id: UInt64): &NonFungibleToken.NFT {
337 return (&self.ownedNFTs[id] as &NonFungibleToken.NFT?)!
338 }
339
340 pub fun borrowAniqueNFT(id: UInt64): auth &Anique.NFT {
341 let nft = (&self.ownedNFTs[id] as auth &NonFungibleToken.NFT?)!
342 return nft as! auth &Anique.NFT
343 }
344
345 // borrowSGKCLDR_bk_2bs_mfCollectible returns a borrowed reference
346 // to an SGKCLDR_bk_2bs_mf Collectible
347 pub fun borrowSGKCLDR_bk_2bs_mfCollectible(id: UInt64): auth &NFT {
348 pre {
349 self.ownedNFTs[id] != nil: "NFT does not exist in the collection!"
350 }
351 let nft = (&self.ownedNFTs[id] as auth &NonFungibleToken.NFT?)!
352 return nft as! auth &NFT
353 }
354
355 // If a transaction destroys the Collection object,
356 // All the NFTs contained within are also destroyed!
357 //
358 destroy() {
359 destroy self.ownedNFTs
360 }
361 }
362
363 // Admin is a special authorization resource that
364 // allows the owner to perform important functions to modify the
365 // various aspects of the Items, CollectibleDatas, etc.
366 //
367 pub resource Admin {
368
369 // createItem creates a new Item struct
370 // and stores it in the Items dictionary field in the SGKCLDR_bk_2bs_mf smart contract
371 //
372 // Parameters: metadata: A dictionary mapping metadata titles to their data
373 // example: {"Title": "Excellent Anime", "Author": "John Smith"}
374 //
375 // Returns: the ID of the new Item object
376 //
377 pub fun createItem(metadata: {String: String}): UInt32 {
378 // Create the new Item
379 var newItem <- create Item(metadata: metadata)
380 let itemId = newItem.itemID
381
382 // Store it in the contract storage
383 SGKCLDR_bk_2bs_mf.items[newItem.itemID] <-! newItem
384
385 return itemId
386 }
387
388 // borrowItem returns a reference to a Item in the SGKCLDR_bk_2bs_mf
389 // contract so that the admin can call methods on it
390 //
391 // Parameters: itemID: The ID of the Item that you want to
392 // get a reference to
393 //
394 // Returns: A reference to the Item with all of the fields
395 // and methods exposed
396 //
397 pub fun borrowItem(itemID: UInt32): &Item {
398 pre {
399 SGKCLDR_bk_2bs_mf.items[itemID] != nil: "Cannot borrow Item: The Item doesn't exist"
400 }
401
402 return (&SGKCLDR_bk_2bs_mf.items[itemID] as &Item?)!
403 }
404
405 // createNewAdmin creates a new Admin resource
406 //
407 pub fun createNewAdmin(): @Admin {
408 return <-create Admin()
409 }
410 }
411
412 // -----------------------------------------------------------------------
413 // SGKCLDR_bk_2bs_mf contract-level function definitions
414 // -----------------------------------------------------------------------
415
416 // createEmptyCollection creates a new, empty Collection object so that
417 // a user can store it in their account storage.
418 // Once they have a Collection in their storage, they are able to receive
419 // Collectibles in transactions.
420 //
421 pub fun createEmptyCollection(): @NonFungibleToken.Collection {
422 return <-create SGKCLDR_bk_2bs_mf.Collection()
423 }
424
425 // getNumCollectiblesInItem return the number of Collectibles that have been
426 // minted from a certain Item.
427 //
428 // Parameters: itemID: The id of the Item that is being searched
429 //
430 // Returns: The total number of Collectibles
431 // that have been minted from a Item
432 pub fun getNumCollectiblesInItem(itemID: UInt32): UInt32 {
433 let item = (&SGKCLDR_bk_2bs_mf.items[itemID] as &Item?)!
434 return item.numberMintedPerItem
435 }
436
437 // -----------------------------------------------------------------------
438 // SGKCLDR_bk_2bs_mf initialization function
439 // -----------------------------------------------------------------------
440 //
441 init() {
442 // Initialize contract fields
443 self.items <- {}
444 self.nextItemID = 1
445 self.totalSupply = 0
446
447 self.collectionStoragePath = /storage/SGKCLDR_bk_2bs_mfCollection
448 self.collectionPublicPath = /public/SGKCLDR_bk_2bs_mfCollection
449 self.collectionPrivatePath = /private/SGKCLDR_bk_2bs_mfCollection
450 self.adminStoragePath = /storage/SGKCLDR_bk_2bs_mfAdmin
451 self.saleCollectionStoragePath = /storage/SGKCLDR_bk_2bs_mfSaleCollection
452 self.saleCollectionPublicPath = /public/SGKCLDR_bk_2bs_mfSaleCollection
453
454 // Put a new Collection in storage
455 self.account.save<@Collection>(<- create Collection(), to: self.collectionStoragePath)
456
457 // Create a public capability for the Collection
458 self.account.link<&{CollectionPublic}>(self.collectionPublicPath, target: self.collectionStoragePath)
459
460 // Put the Admin in storage
461 self.account.save<@Admin>(<- create Admin(), to: self.adminStoragePath)
462
463 emit ContractInitialized()
464 }
465}
466