Smart Contract
MintStoreItem
A.20187093790b9aef.MintStoreItem
1/*
2 Description:
3
4 authors: Matthew Balazsi (matthew@mint.store), Joseph Djenandji (joseph@mint.store)
5
6 This smart contract contains the core functionality for Mint Store NFTs.
7
8 MINT is a platform where teams can create a fully branded environment to sell NFTs and launch branded marketplaces.
9 This will give fans a fully immersive experience as they interact with drops, buy and sell in the marketplace, and
10 deepen their relationships with the brand.
11
12 NFTs will be minted in groups called Editions. Each item in the edition will contain identical metadata except for
13 the editionNumber (or print number). Editions can either be open (no limit to number of items minted), or closed
14 (only a fixed number of items can be printed).
15
16 When a new NFT needs to be minted...
17 Here is the Recipe for the Mint Julep:
18 1 teaspoon Powdered sugar
19 2 oz. Bourbon whiskey
20 2 teaspoons Water
21 4 Mint leaves
22
23 Enjoy!
24*/
25
26// import NonFungibleToken from "./NonFungibleToken.cdc"
27// import FungibleToken from "./FungibleToken.cdc"
28// import MetadataViews from "./MetadataViews.cdc"
29
30// for tests
31// import NonFungibleToken from "0xNonFungibleToken"
32// import ViewResolver from "0xViewResolver"
33// import MetadataViews from "0xMetadataViews"
34
35// for testnet
36
37// import NonFungibleToken from 0x631e88ae7f1d7c20
38// import MetadataViews from 0x631e88ae7f1d7c20
39// import ViewResolver from 0x631e88ae7f1d7c20
40
41// for mainnet
42import NonFungibleToken from 0x1d7e57aa55817448
43import MetadataViews from 0x1d7e57aa55817448
44import ViewResolver from 0x1d7e57aa55817448
45
46
47access(all) contract MintStoreItem: NonFungibleToken {
48
49 // -----------------------------------------------------------------------
50 // MintStoreItem contract Events
51 // -----------------------------------------------------------------------
52
53 // Emitted when the MintStoreItem contract is created
54 access(all) event ContractInitialized()
55
56 // Emitted when a new Edition struct is created
57 access(all) event EditionCreated(id: UInt32, name: String, printingLimit: UInt32?)
58
59 // Emitted when Edition Metadata is updated
60 access(all) event EditionMetadaUpdated(editionID: UInt32)
61
62 // Emitted when a new Merchant is created
63 access(all) event MerchantCreated(merchantID: UInt32, name: String)
64
65
66 // Emitted when a new Merchant is updated
67 access(all) event MerchantUpdated(merchantID: UInt32, name: String)
68
69
70 // Emitted when a new item was minted
71 access(all) event ItemMinted(itemID:UInt64, merchantID: UInt32, editionID: UInt32, editionNumber: UInt32)
72
73 // Item related events
74 //
75 // Emitted when an Item is withdrawn from a Collection
76 access(all) event Withdraw(id: UInt64, from: Address?)
77 // Emitted when an Item is deposited into a Collection
78 access(all) event Deposit(id: UInt64, to: Address?)
79 // Emitted when an Item is destroyed
80 access(all) event ItemDestroyed(id: UInt64)
81
82
83 // Named paths
84 //
85 access(all) let CollectionStoragePath: StoragePath
86 access(all) let CollectionPublicPath: PublicPath
87 access(all) let AdminStoragePath: StoragePath
88
89
90 // -----------------------------------------------------------------------
91 // MintStoreItem contract-level fields.
92 // These contain actual values that are stored in the smart contract.
93 // -----------------------------------------------------------------------
94
95 // Variable size dictionary of Editions resources
96 access(self) var editions: @{UInt32: Edition}
97
98
99 // The ID that is used to create Admins.
100 // Every Admins should have a unique identifier.
101 access(all) var nextAdminID: UInt32
102
103
104
105 // The ID that is used to create Editions.
106 // Every time an Edition is created, nextEditionID is assigned
107 // to the edition and then is incremented by 1.
108 access(all) var nextEditionID: UInt32
109
110
111 // Variable size dictionary of Merchant names
112 access(self) var merchants: {UInt32: String}
113
114 // The ID that is used to create Merchants.
115 // Every time a Merchant is created, nextMerchantID is assigned
116 // to the merchant and then is incremented by 1.
117 access(all) var nextMerchantID: UInt32
118
119
120 // The total number of MintStoreItem NFTs that have been created
121 // Because NFTs can be destroyed, it doesn't necessarily mean that this
122 // reflects the total number of NFTs in existence, just the number that
123 // have been minted to date. Also used as global nft IDs for minting.
124 access(all) var totalSupply: UInt64
125
126
127 // -----------------------------------------------------------------------
128 // MintStoreItem contract-level Composite Type definitions
129 // -----------------------------------------------------------------------
130 // These are just *definitions* for Types that this contract
131 // and other accounts can use. These definitions do not contain
132 // actual stored values, but an instance (or object) of one of these Types
133 // can be created by this contract that contains stored values.
134 // -----------------------------------------------------------------------
135
136
137 // EditionData is a struct definition to have all of the same fields as the Edition resource.
138 // it can be used to publicly read Edition data
139
140 access(all) struct EditionData {
141 access(all) let editionID: UInt32
142 access(all) let merchantID: UInt32
143 access(all) let name: String
144 access(all) var items: [UInt64]
145 access(all) var metadata: {String: String}
146 access(all) var numberOfItemsMinted: UInt32
147 access(all) var printingLimit: UInt32?
148
149 init(editionID: UInt32) {
150
151 if MintStoreItem.editions[editionID] == nil {
152 panic("the editionID was not found")
153 }
154 let editionToRead = (&MintStoreItem.editions[editionID] as &Edition?)!
155
156 self.editionID = editionID
157 self.metadata = MintStoreItem.editions[editionID]?.metadata ?? ({} as {String: String})
158 self.merchantID = editionToRead.merchantID
159 self.name = editionToRead.name
160 self.printingLimit = editionToRead.printingLimit
161 self.numberOfItemsMinted=editionToRead.numberOfItemsMinted
162 self.items =MintStoreItem.editions[editionID]?.items ?? ([] as [UInt64])
163 }
164 }
165 // Edition is a Ressource that holds metadata associated
166 // with a specific MintStoreItem
167 //
168 // MintStore NFTs will all reference an Edition as the owner of
169 // its metadata. The Editions are publicly accessible, so anyone can
170 // read the metadata associated with a specific EditionID
171 //
172 access(all) resource Edition {
173
174 // The unique ID for the Edition
175 access(all) let editionID: UInt32
176
177 // The ID of the merchant that owns the edition
178 access(all) let merchantID: UInt32
179
180 // Stores all the metadata about the edition as a string mapping
181 // This is not the long term way NFT metadata will be stored. It's a temporary
182 // construct while we figure out a better way to do metadata.
183 //
184 access(all) let metadata: {String: String}
185
186 // Array of items that are a part of this collection.
187 // When an item is added to the collection, its ID gets appended here.
188 access(all) var items: [UInt64]
189
190 // The number of items minted in this collection.
191 // When an item is added to the collection, the numberOfItems is incremented by 1
192 // It will be used to identify the editionNumber of an item
193 // if the edition is open (printingLimit=nil), we can keep minting new items
194 // if the edition is limited (printingLimit!=nil), we can keep minting items until we reach printingLimit
195 access(all) var numberOfItemsMinted: UInt32
196
197
198 // the limit of items that can be minted. For open editions, this value should be set to nil.
199 access(all) var printingLimit: UInt32?
200
201 // the name of the edition
202 access(all) var name: String
203
204 init(merchantID: UInt32, metadata: {String: String}, name: String, printingLimit:UInt32?) {
205 pre {
206 metadata.length != 0: "Metadata cannot be empty"
207 name!=nil: "Name is undefined"
208 }
209 self.editionID = MintStoreItem.nextEditionID
210 self.merchantID = merchantID
211 self.metadata = metadata
212 self.name = name
213 self.printingLimit = printingLimit
214 self.numberOfItemsMinted=0
215 self.items = []
216
217
218 // Increment the ID so that it isn't used again
219 MintStoreItem.nextEditionID = MintStoreItem.nextEditionID + (1 as UInt32)
220
221 emit EditionCreated(id: self.editionID, name: self.name, printingLimit: self.printingLimit)
222 }
223
224
225 // mintItem mints a new Item and returns the newly minted Item
226 //
227 // Pre-Conditions:
228 // If the edition is limited the number of items minted in the edition must be strictly less than the printing limit
229 //
230 // Returns: The NFT that was minted
231 //
232 access(all) fun mintItem(): @NFT {
233 pre {
234 (self.numberOfItemsMinted < (self.printingLimit ?? (4294967295 as UInt32) )): "We have reached the printing limit for this edition"
235 }
236
237 // Gets the number of Itms that have been minted for this Edition
238 // to use as this Item's edition number
239 let numMinted = self.numberOfItemsMinted + (1 as UInt32)
240
241 // Mint the new item
242 let newItem: @NFT <- create NFT(merchantID: self.merchantID, editionID: self.editionID, editionNumber: numMinted)
243
244
245 // Add the Item to the array of items
246 self.items.append(newItem.id)
247
248 // Increment the count of Items
249 self.numberOfItemsMinted = numMinted
250
251 return <-newItem
252 }
253
254 // batchMintItems mints an arbitrary quantity of Items
255 // and returns them as a Collection
256 // Be sure there are enough
257 //
258 // Parameters: quantity: The quantity of Items to be minted
259 //
260 // Returns: Collection object that contains all the Items that were minted
261 //
262 access(all) fun batchMintItems(quantity: UInt32): @Collection {
263
264 pre {
265 ((self.numberOfItemsMinted+quantity)<=(self.printingLimit ?? (4294967295 as UInt32))): "We have reached the printing limit for this edition"
266 }
267
268 let newCollection <- create Collection()
269
270 var i: UInt32 = 0
271 while i < quantity {
272 newCollection.deposit(token: <-self.mintItem())
273 i = i + (1 as UInt32)
274 }
275
276 return <-newCollection
277 }
278
279 // updateMetadata updates the metadata
280 //
281 // Parameters:
282 //
283 // updates: a dictionary of key - values that is requested to be appended
284 //
285 // suffix: If the metadata already contains an attribute with a given key, this value should still be kept
286 // for posteriority. Therefore, the old value to be replaced will be stored in a metadata entry with key = key+suffix.
287 // This can offer some reassurance to the NFT owner that the metadata will never disappear.
288 //
289 // Returns: the EditionID
290 //
291 access(all) fun updateMetadata(updates: {String:String}, suffix: String): UInt32 {
292
293
294
295 // prevalidation
296 // if metadata[key] exists and metadata[key+suffix] exists, we have a clash.
297 for key in updates.keys {
298
299 let newKey = key.concat(suffix)
300
301 if self.metadata[key] != nil && self.metadata[newKey]!=nil {
302 var errorMsg = "attributes "
303 errorMsg = errorMsg.concat(key).concat(" and ").concat(newKey).concat(" are already defined")
304 panic(errorMsg)
305 }
306
307
308 }
309
310 // execution
311 for key in updates.keys {
312
313 let newKey = key.concat(suffix)
314
315 if self.metadata[key] != nil {
316 self.metadata[newKey] = self.metadata[key]
317 }
318 self.metadata[key] = updates[key]
319
320 }
321
322
323 emit EditionMetadaUpdated(editionID: self.editionID)
324
325 // Return the EditionID and return it
326 return self.editionID
327 }
328
329 }
330
331 // The struct representing an NFT Item data
332 access(all) struct ItemData {
333
334
335 // The ID of the merchant
336 access(all) let merchantID: UInt32
337
338 // The ID of the edition that the NFT comes from
339 access(all) let editionID: UInt32
340
341 // The number of the NFT within the edition
342 access(all) let editionNumber: UInt32
343
344
345
346 init(merchantID: UInt32, editionID: UInt32, editionNumber: UInt32) {
347 self.merchantID = merchantID
348 self.editionID = editionID
349 self.editionNumber = editionNumber
350 }
351
352 }
353
354 // The resource that represents the Item NFTs
355 //
356 access(all) resource NFT: NonFungibleToken.NFT {
357
358 // Global unique item ID
359 access(all) let id: UInt64
360
361 // Struct of MintStoreItem metadata
362 access(all) let data: ItemData
363
364
365 init(merchantID: UInt32, editionID: UInt32, editionNumber: UInt32) {
366
367 pre{
368 editionID > (0 as UInt32): "editionID cannot be 0"
369 editionNumber > (0 as UInt32): "editionNumber cannot be 0"
370 }
371 // Increment the global Item IDs
372 MintStoreItem.totalSupply = MintStoreItem.totalSupply + (1 as UInt64)
373
374 self.id = MintStoreItem.totalSupply
375
376 // Set the metadata struct
377 self.data = ItemData(merchantID: merchantID, editionID: editionID, editionNumber: editionNumber)
378
379
380 emit ItemMinted(itemID: self.id, merchantID: merchantID, editionID: editionID, editionNumber: editionNumber)
381 }
382
383 access(all) view fun getData(): ItemData {
384 return self.data
385 }
386
387 /// createEmptyCollection creates an empty Collection
388 /// and returns it to the caller so that they can own NFTs
389 /// @{NonFungibleToken.Collection}
390 access(all) fun createEmptyCollection(): @{NonFungibleToken.Collection} {
391 return <-MintStoreItem.createEmptyCollection(nftType: Type<@MintStoreItem.NFT>())
392 }
393
394
395 access(all) view fun getViews(): [Type] {
396 return [
397 Type<MetadataViews.Display>(),
398 Type<MetadataViews.Royalties>(),
399 Type<MetadataViews.Editions>(),
400 Type<MetadataViews.ExternalURL>(),
401 Type<MetadataViews.NFTCollectionData>(),
402 Type<MetadataViews.NFTCollectionDisplay>(),
403 Type<MetadataViews.Serial>(),
404 Type<MetadataViews.Traits>()
405 ]
406 }
407
408
409 access(all) fun resolveView(_ view: Type): AnyStruct? {
410 switch view {
411 case Type<MetadataViews.Display>():
412 let edition = EditionData(editionID: self.data.editionID);
413 return MetadataViews.Display(
414 name: edition.name,
415 description: edition.metadata["description"] ?? "",
416 thumbnail: MetadataViews.HTTPFile(
417 url: edition.metadata["thumbnail"] ?? ""
418 )
419 )
420 case Type<MetadataViews.Editions>():
421 // There is no max number of NFTs that can be minted from this contract
422 // so the max edition field value is set to nil
423 let edition = EditionData(editionID: self.data.editionID);
424 let maxNumber = edition.printingLimit ?? nil
425 var max: UInt64? = nil;
426 if maxNumber != nil {
427 max = UInt64(maxNumber!)
428 }
429
430
431 let editionInfo = MetadataViews.Edition(name: edition.name, number: UInt64(self.data.editionNumber), max:max)
432 let editionList: [MetadataViews.Edition] = [editionInfo]
433 return MetadataViews.Editions(
434 editionList
435 )
436
437 case Type<MetadataViews.Royalties>():
438
439 // TODO: add Royalties to editionData.
440 // For now, we have royalty address and royalty percentage in the metadata
441 // However, we have issues converting the String to Address and to UFix64
442 return MetadataViews.Royalties([])
443
444 case Type<MetadataViews.ExternalURL>():
445 let edition = EditionData(editionID: self.data.editionID);
446 let url = edition.metadata["externalUrl"] ?? "";
447 return MetadataViews.ExternalURL(url)
448
449 case Type<MetadataViews.NFTCollectionData>():
450 return MetadataViews.NFTCollectionData(
451 storagePath: MintStoreItem.CollectionStoragePath,
452 publicPath: MintStoreItem.CollectionPublicPath,
453 publicCollection: Type<&MintStoreItem.Collection>(),
454 publicLinkedType: Type<&MintStoreItem.Collection>(),
455 createEmptyCollectionFunction: (fun (): @{NonFungibleToken.Collection} {
456 return <-MintStoreItem.createEmptyCollection(nftType: Type<@MintStoreItem.NFT>())
457 })
458 )
459
460 case Type<MetadataViews.NFTCollectionDisplay>():
461
462 let edition = EditionData(editionID: self.data.editionID);
463 let merchantName = MintStoreItem.merchants[self.data.merchantID]!
464 let thumbnail = edition.metadata["thumbnail"] ?? "";
465 let media = MetadataViews.Media(
466 file: MetadataViews.HTTPFile(
467 url: thumbnail
468 ),
469 mediaType: "image/png"
470 )
471 let url = edition.metadata["externalUrl"] ?? "";
472 let description = edition.metadata["description"] ?? "";
473
474
475 return MetadataViews.NFTCollectionDisplay(
476 name: merchantName,
477 description: description,
478 externalURL: MetadataViews.ExternalURL(url),
479 squareImage: media,
480 bannerImage: media,
481 socials: {}
482 )
483
484 case Type<MetadataViews.Traits>():
485 // exclude mintedTime and foo to show other uses of Traits
486 let excludedTraits = ["name", "description", "thumbnail", "externalUrl"]
487 let edition = EditionData(editionID: self.data.editionID);
488 let metadata = edition.metadata;
489
490 metadata.insert(key: "editionID", edition.editionID.toString());
491 metadata.insert(key: "merchantID", edition.merchantID.toString());
492
493 let traitsView = MetadataViews.dictToTraits(dict: metadata, excludedNames: excludedTraits)
494
495 return traitsView
496
497
498 }
499
500 return nil
501 }
502
503
504 }
505
506 access(all) view fun getContractViews(resourceType: Type?): [Type] {
507 return []
508 }
509
510 access(all) fun resolveContractView(resourceType: Type?, viewType: Type): AnyStruct? {
511
512 return nil
513 }
514
515 // Admin is a special authorization resource that
516 // allows the owner to perform important functions to modify the
517 // various aspects of the Editions and Items
518 //
519 access(all) resource Admin {
520
521 access(all) let id: UInt32
522 // createEdition creates a new Edition struct
523 // and stores it in the Editions dictionary in the MintStore contract
524 //
525
526 init(id: UInt32) {
527 self.id = id
528 }
529
530
531 // createEdition creates a new Edition resource and stores it
532 // in the editions mapping in the MintStoreItem contract
533 //
534 // Parameters:
535 // merchantID: The ID of the merchant
536 // metadata: the associated data
537 // name: The name of the Edition
538 // printingLimit: We can only mint this quantity of NFTs. If printingLimit is nil there is no limit (theoretically UInt32.max)
539 //
540 access(all) fun createEdition(merchantID: UInt32, metadata: {String: String}, name: String, printingLimit: UInt32?) {
541 // Create the new Edition
542 var newEdition <- create Edition(merchantID:merchantID, metadata: metadata, name: name, printingLimit:printingLimit)
543 let newID = newEdition.editionID
544
545 // Store it in the contract storage
546 MintStoreItem.editions[newID] <-! newEdition
547
548 }
549
550
551 // borrowEdition returns a reference to an edition in the MintStoreItem
552 // contract so that the admin can call methods on it
553 //
554 // Parameters: editionID: The ID of the Edition that you want to
555 // get a reference to
556 //
557 // Returns: A reference to the Edition with all of the fields
558 // and methods exposed
559 //
560 access(all) fun borrowEdition(editionID: UInt32): &Edition {
561 pre {
562 MintStoreItem.editions[editionID] != nil: "Cannot borrow Edition: it does not exist"
563 }
564
565 // Get a reference to the Edition and return it
566 return (&MintStoreItem.editions[editionID] as &Edition?)!
567 }
568
569 // updateEditionMetadata returns a reference to an edition in the MintStoreItem
570 // contract so that the admin can call methods on it
571 //
572 // Parameters:
573 // editionID: The ID of the Edition that you want to update
574 //
575 // updates: a dictionary of key - values that is requested to be appended
576 //
577 // suffix: If the metadata already contains an attribute with a given key, this value should still be kept
578 // for posteriority. Therefore, the old value to be replaced will be stored in a metadata entry with key = key+suffix.
579 // This can offer some reassurance to the NFT owner that the metadata will never disappear.
580 //
581 // Returns: the EditionID
582 //
583 access(all) fun updateEditionMetadata(editionID: UInt32, updates: {String:String}, suffix: String): UInt32 {
584 pre {
585 MintStoreItem.editions[editionID] != nil: "Cannot borrow Edition: it does not exist"
586 }
587
588 let editionRef = &MintStoreItem.editions[editionID] as &Edition?
589 editionRef!.updateMetadata(updates: updates, suffix: suffix)
590
591 // Return the EditionID and return it
592 return editionID
593 }
594
595
596 access(all) fun createMerchant(merchantName: String): UInt32 {
597
598 pre {
599 merchantName != nil: "Cannot create the merchant: merchantName is nil"
600 }
601 let newID = MintStoreItem.nextMerchantID
602
603
604 // Create the new Merchant
605 MintStoreItem.merchants[newID] = merchantName
606
607 // Increment the ID so that it isn't used again
608 MintStoreItem.nextMerchantID = MintStoreItem.nextMerchantID + (1 as UInt32)
609
610 emit MerchantCreated(merchantID: newID, name: merchantName)
611 return newID
612 }
613
614
615 access(all) fun updateMerchant(merchantID: UInt32, merchantName: String): UInt32 {
616
617 pre {
618 MintStoreItem.merchants[merchantID] !=nil: "Cannot upate the merchant: merchantID is not initialized"
619 merchantName != nil: "Cannot upate the merchant: merchantName is nil"
620 }
621
622 // Update the new Merchant
623 MintStoreItem.merchants[merchantID] = merchantName
624
625 emit MerchantUpdated(merchantID: merchantID, name: merchantName)
626 return merchantID
627 }
628
629
630
631 // createNewAdmin creates a new Admin resource
632 //
633 access(all) fun createNewAdmin(): @Admin {
634
635
636 let newID = MintStoreItem.nextAdminID
637 // Increment the ID so that it isn't used again
638 MintStoreItem.nextAdminID = MintStoreItem.nextAdminID + (1 as UInt32)
639
640 return <-create Admin(id: newID)
641 }
642
643 }
644
645
646
647 // This is the interface that users can cast their MintStoreItem Collection as
648 // to allow others to deposit MintStoreItems into their Collection. It also allows for reading
649 // the IDs of MintStoreItems in the Collection.
650 access(all) resource interface MintStoreItemCollectionPublic {
651
652
653 }
654
655
656
657 // Collection is a resource that every user who owns NFTs
658 // will store in their account to manage their NFTS
659 //
660 access(all) resource Collection: NonFungibleToken.Collection, MintStoreItemCollectionPublic {
661 // Dictionary of MintStore conforming tokens
662 // NFT is a resource type with a UInt64 ID field
663 access(all) var ownedNFTs: @{UInt64: {NonFungibleToken.NFT}}
664 // access(all) var ownedNFTs: @{UInt64: MintStoreItem.NFT}
665
666 init() {
667 self.ownedNFTs <- {}
668 }
669
670
671
672
673 // withdraw removes a MintStoreItem from the Collection and moves it to the caller
674 //
675 // Parameters: withdrawID: The ID of the NFT
676 // that is to be removed from the Collection
677 //
678 // returns: @NonFungibleToken.NFT the token that was withdrawn
679 access(NonFungibleToken.Withdraw) fun withdraw(withdrawID: UInt64): @{NonFungibleToken.NFT} {
680
681 // Remove the nft from the Collection
682 let token <- self.ownedNFTs.remove(key: withdrawID)
683 ?? panic("Cannot withdraw: MintStoreItem does not exist in the collection")
684
685 emit Withdraw(id: token.id, from: self.owner?.address)
686
687 // Return the withdrawn token
688 return <-token
689 }
690
691 // batchWithdraw withdraws multiple tokens and returns them as a Collection
692 //
693 // Parameters: ids: An array of IDs to withdraw
694 //
695 // Returns: @NonFungibleToken.Collection: A collection that contains
696 // the withdrawn MintStore items
697 //
698 access(NonFungibleToken.Withdraw) fun batchWithdraw(ids: [UInt64]): @{NonFungibleToken.Collection} {
699 // Create a new empty Collection
700 var batchCollection <- create Collection()
701
702 // Iterate through the ids and withdraw them from the Collection
703 for id in ids {
704
705 let token <-self.withdraw(withdrawID: id)
706
707 batchCollection.deposit(token: <-token)
708 }
709
710 // Return the withdrawn tokens
711 return <-batchCollection
712 }
713
714 /// getSupportedNFTTypes returns a list of NFT types that this receiver accepts
715 access(all) view fun getSupportedNFTTypes(): {Type: Bool} {
716 let supportedTypes: {Type: Bool} = {}
717 supportedTypes[Type<@MintStoreItem.NFT>()] = true
718 return supportedTypes
719 }
720
721 /// Returns whether or not the given type is accepted by the collection
722 /// A collection that can accept any type should just return true by default
723 access(all) view fun isSupportedNFTType(type: Type): Bool {
724 return type == Type<@MintStoreItem.NFT>()
725 }
726
727 /// Gets the amount of NFTs stored in the collection
728 access(all) view fun getLength(): Int {
729 return self.ownedNFTs.length
730 }
731
732
733 // deposit takes a MintStoreItem and adds it to the Collections dictionary
734 //
735 // Paramters: token: the NFT to be deposited in the collection
736 //
737 access(all) fun deposit(token: @{NonFungibleToken.NFT}) {
738
739 // Cast the deposited token as a MintStoreItem NFT to make sure
740 // it is the correct type
741 let token <- token as! @MintStoreItem.NFT
742
743 // Get the token's ID
744 let id = token.id
745
746 // Add the new token to the dictionary
747 let oldToken <- self.ownedNFTs[id] <- token
748
749 // Only emit a deposit event if the Collection
750 // is in an account's storage
751 if self.owner?.address != nil {
752 emit Deposit(id: id, to: self.owner?.address)
753 }
754
755 // Destroy the empty old token that was "removed"
756 destroy oldToken
757 }
758
759 // batchDeposit takes a Collection object as an argument
760 // and deposits each contained NFT into this Collection
761 access(all) fun batchDeposit(tokens: @{NonFungibleToken.Collection}) {
762
763 // Get an array of the IDs to be deposited
764 let keys = tokens.getIDs()
765
766 // Iterate through the keys in the collection and deposit each one
767 for key in keys {
768 self.deposit(token: <-tokens.withdraw(withdrawID: key))
769 }
770
771 // Destroy the empty Collection
772 destroy tokens
773 }
774
775 // getIDs returns an array of the IDs that are in the Collection
776 access(all) view fun getIDs(): [UInt64] {
777 return self.ownedNFTs.keys
778 }
779
780 // borrowNFT Returns a borrowed reference to a MintStoreItem in the Collection
781 // so that the caller can read its ID
782 //
783 // Parameters: id: The ID of the NFT to get the reference for
784 //
785 // Returns: A reference to the NFT
786 //
787 // Note: This only allows the caller to read the ID of the NFT,
788 // not any MintStoreItem specific data. Please use borrowMintStoreItem to
789 // read MintStoreItem data.
790 //
791 access(all) view fun borrowNFT(_ id: UInt64): &{NonFungibleToken.NFT}? {
792 return (&self.ownedNFTs[id] as &{NonFungibleToken.NFT}?)
793 }
794
795 // borrowMintStoreItem returns a borrowed reference to a MintStoreItem
796 // so that the caller can read data and call methods from it.
797 // They can use this to read its editionID, editionNumber,
798 // or any edition data associated with it by
799 // getting the editionID and reading those fields from
800 // the smart contract.
801 //
802 // Parameters: id: The ID of the NFT to get the reference for
803 //
804 // // Returns: A reference to the NFT
805 // access(all) fun borrowMintStoreItem(id: UInt64): &MintStoreItem.NFT? {
806 // if self.ownedNFTs[id] != nil {
807 // let ref = (&self.ownedNFTs[id] as auth &NonFungibleToken.NFT?)!
808 // return ref as! &MintStoreItem.NFT
809 // } else {
810 // return nil
811 // }
812 // }
813
814/// Borrow the view resolver for the specified NFT ID
815 access(all) view fun borrowViewResolver(id: UInt64): &{ViewResolver.Resolver}? {
816 if let nft = &self.ownedNFTs[id] as &{NonFungibleToken.NFT}? {
817 return nft as &{ViewResolver.Resolver}
818 }
819 return nil
820 }
821
822 /// createEmptyCollection creates an empty Collection of the same type
823 /// and returns it to the caller
824 /// @return A an empty collection of the same type
825 access(all) fun createEmptyCollection(): @{NonFungibleToken.Collection} {
826 return <-MintStoreItem.createEmptyCollection(nftType: Type<@MintStoreItem.NFT>())
827 }
828
829
830 }
831
832
833
834 // -----------------------------------------------------------------------
835 // MintStoreItem contract-level function definitions
836 // -----------------------------------------------------------------------
837
838 // createEmptyCollection creates a new, empty Collection object so that
839 // a user can store it in their account storage.
840 // Once they have a Collection in their storage, they are able to receive
841 // MintStoreItems in transactions.
842 //
843 access(all) fun createEmptyCollection(nftType: Type): @{NonFungibleToken.Collection} {
844 return <- create MintStoreItem.Collection()
845 }
846
847 access(all) fun createEmptyMintStoreItemCollection(): @MintStoreItem.Collection {
848 return <-create MintStoreItem.Collection()
849 }
850
851
852
853 // getMerchantIDs returns an array of the merchant IDs
854 access(all) fun getMerchantIDs(): [UInt32] {
855 return self.merchants.keys
856 }
857
858 // getMerchantNames returns an array of the merchant Names
859 access(all) fun getMerchantNames(): [String] {
860 return self.merchants.values
861 }
862
863 // getMerchant returns the merchant name with a given merchantID
864 access(all) fun getMerchant(merchantID: UInt32): String? {
865 return self.merchants[merchantID]
866 }
867
868
869 // -----------------------------------------------------------------------
870 // MintStoreItem initialization function
871 // -----------------------------------------------------------------------
872 //
873 init() {
874 // Initialize contract fields
875 self.editions <- {}
876 self.nextEditionID = 1
877 self.totalSupply = 0
878 self.merchants = {}
879 self.nextMerchantID = 1
880
881
882 self.CollectionStoragePath = /storage/MintStoreItemCollection
883 self.CollectionPublicPath = /public/MintStoreItemCollection
884 self.AdminStoragePath = /storage/MintStoreItemAdmin
885
886 // Put a new Collection in storage
887 self.account.storage.save<@Collection>(<- create Collection(), to: self.CollectionStoragePath)
888
889 // Create a public capability for the Collection
890 // self.account.link<&{MintStoreItemCollectionPublic}>(self.CollectionPublicPath, target: self.CollectionStoragePath)
891 let collectionCap = self.account.capabilities.storage.issue<&MintStoreItem.Collection>(self.CollectionStoragePath)
892 self.account.capabilities.publish(collectionCap, at: self.CollectionPublicPath)
893
894 // Put the admin ressource in storage
895 self.account.storage.save<@Admin>(<- create Admin(id: 1), to: self.AdminStoragePath)
896 self.nextAdminID = 2
897
898 emit ContractInitialized()
899 }
900
901
902}
903
904
905