Smart Contract
TicalUniverse
A.fef48806337aabf1.TicalUniverse
1import NonFungibleToken from 0x1d7e57aa55817448
2import MetadataViews from 0x1d7e57aa55817448
3import ViewResolver from 0x1d7e57aa55817448
4
5access(all) contract TicalUniverse: NonFungibleToken {
6
7 // -----------------------------------------------------------------------
8 // TicalUniverse contract Paths
9 // -----------------------------------------------------------------------
10
11 access(all) let CollectionStoragePath: StoragePath
12 access(all) let CollectionPublicPath: PublicPath
13 access(all) let AdminPublicPath: PublicPath
14 access(all) let AdminStoragePath: StoragePath
15
16 // -----------------------------------------------------------------------
17 // TicalUniverse contract Events
18 // -----------------------------------------------------------------------
19
20 // Emitted when the TicalUniverse contract is created
21 access(all) event ContractInitialized()
22
23 // Emitted when a new Item struct is created
24 access(all) event ItemCreated(id: UInt32, metadata: {String:String})
25 // Emitted when a new series has been started
26 access(all) event NewSeriesStarted(newCurrentSeries: UInt32)
27
28 // Events for Set-Related actions
29 //
30 // Emitted when a new Set is created
31 access(all) event SetCreated(setId: UInt32, series: UInt32)
32 // Emitted when a new Item is added to a Set
33 access(all) event ItemAddedToSet(setId: UInt32, itemId: UInt32)
34 // Emitted when an Item is retired from a Set and cannot be used to mint
35 access(all) event ItemRetiredFromSet(setId: UInt32, itemId: UInt32, minted: UInt32)
36 // Emitted when a Set is locked, meaning collectibles cannot be added
37 access(all) event SetLocked(setId: UInt32)
38 // Emitted when a collectible is minted from a Set
39 access(all) event CollectibleMinted(id: UInt64, itemId: UInt32, setId: UInt32, serialNumber: UInt32)
40
41 // Events for Collection-related actions
42 //
43 // Emitted when a collectible is withdrawn from a Collection
44 access(all) event Withdraw(id: UInt64, from: Address?)
45 // Emitted when a collectible is deposited into a Collection
46 access(all) event Deposit(id: UInt64, to: Address?)
47
48 // -----------------------------------------------------------------------
49 // TicalUniverse contract-level fields.
50 // These contain actual values that are stored in the smart contract.
51 // -----------------------------------------------------------------------
52
53 // Series that this Set belongs to.
54 // Many Sets can exist at a time, but only one series.
55 access(all) var currentSeries: UInt32
56
57 // Variable size dictionary of Item structs
58 access(self) var itemDatas: {UInt32: Item}
59
60 // Variable size dictionary of SetData structs
61 access(self) var setDatas: {UInt32: SetData}
62
63 // Variable size dictionary of Set resources
64 access(self) var sets: @{UInt32: Set}
65
66 // The Id that is used to create Items.
67 // Every time an Item is created, nextItemId is assigned
68 // to the new Item's Id and then is incremented by one.
69 access(all) var nextItemId: UInt32
70
71 // The Id that is used to create Sets.
72 // Every time a Set is created, nextSetId is assigned
73 // to the new Set's Id and then is incremented by one.
74 access(all) var nextSetId: UInt32
75
76 // The total number of Collectible NFTs that have been created
77 // Because NFTs can be destroyed, it doesn't necessarily mean that this
78 // reflects the total number of NFTs in existence, just the number that
79 // have been minted to date.
80 access(all) var totalSupply: UInt64
81
82 // -----------------------------------------------------------------------
83 // TicalUniverse contract-level Composite Type definitions
84 // -----------------------------------------------------------------------
85 // These are just *definitions* for Types that this contract
86 // and other accounts can use. These definitions do not contain
87 // actual stored values, but an instance (or object) of one of these Types
88 // can be created by this contract that contains stored values.
89 // -----------------------------------------------------------------------
90
91 // Item is a Struct that holds metadata associated with a specific collectible item.
92 access(all) struct Item {
93
94 // The unique Id for the Item
95 access(all) let itemId: UInt32
96
97 // Stores all the metadata about the item as a string mapping.
98 access(all) let metadata: {String: String}
99
100 init(metadata: {String: String}) {
101 pre {
102 metadata.length != 0: "New Item metadata cannot be empty"
103 }
104 self.itemId = TicalUniverse.nextItemId
105 self.metadata = metadata
106
107 // Increment the Id so that it isn't used again
108 TicalUniverse.nextItemId = TicalUniverse.nextItemId + UInt32(1)
109
110 emit ItemCreated(id: self.itemId, metadata: metadata)
111 }
112 }
113
114 // A Set is a grouping of Items that make up a related group of collectibles,
115 // like sets of baseball cards.
116 // An Item can exist in multiple different sets.
117 //
118 // SetData is a struct that is stored in a field of the contract.
119 // Anyone can query the constant information
120 // about a set by calling various getters located
121 // at the end of the contract. Only the admin has the ability
122 // to modify any data in the private Set resource.
123 access(all) struct SetData {
124
125 // Unique Id for the Set
126 access(all) let setId: UInt32
127
128 // Name of the Set
129 access(all) let name: String
130
131 // Description of the Set
132 access(all) let description: String?
133
134 // Series that this Set belongs to
135 access(all) let series: UInt32
136
137 init(name: String, description: String?) {
138 pre {
139 name.length > 0: "New Set name cannot be empty"
140 }
141 self.setId = TicalUniverse.nextSetId
142 self.name = name
143 self.description = description
144 self.series = TicalUniverse.currentSeries
145
146 // Increment the setId so that it isn't used again
147 TicalUniverse.nextSetId = TicalUniverse.nextSetId + UInt32(1)
148
149 emit SetCreated(setId: self.setId, series: self.series)
150 }
151 }
152
153 // Set is a resource type that contains the functions to add and remove
154 // Items from a set and mint Collectibles.
155 //
156 // It is stored in a private field in the contract so that
157 // the admin resource can call its methods.
158 //
159 // The admin can add Items to a Set so that the set can mint Collectibles.
160 // The Collectible that is minted by a Set will be listed as belonging to
161 // the Set that minted it, as well as the Item it reference.
162 //
163 // Admin can also retire Items from the Set, meaning that the retired
164 // Item can no longer have Collectibles minted from it.
165 //
166 // If the admin locks the Set, no more Items can be added to it, but
167 // Collectibles can still be minted.
168 //
169 // If retireAll() and lock() are called back-to-back,
170 // the Set is closed off forever and nothing more can be done with it.
171 access(all) resource Set {
172
173 // Unique Id for the set
174 access(all) let setId: UInt32
175
176 // Array of items that are a part of this set.
177 // When an item is added to the set, its Id gets appended here.
178 // The Id does not get removed from this array when an Item is retired.
179 access(all) var items: [UInt32]
180
181 // Map of Item Ids that indicates if an Item in this Set can be minted.
182 // When an Item is added to a Set, it is mapped to false (not retired).
183 // When an Item is retired, this is set to true and cannot be changed.
184 access(all) var retired: {UInt32: Bool}
185
186 // Indicates if the Set is currently locked.
187 // When a Set is created, it is unlocked and Items are allowed to be added to it.
188 // When a set is locked, Items cannot be added to it.
189 // A Set can't transition from locked to unlocked. Locking is final.
190 // If a Set is locked, Items cannot be added, but Collectibles can still be minted
191 // from Items that exist in the Set.
192 access(all) var locked: Bool
193
194 // Mapping of Item Ids that indicates the number of Collectibles
195 // that have been minted for specific Items in this Set.
196 // When a Collectible is minted, this value is stored in the Collectible to
197 // show its place in the Set, eg. 42 of 100.
198 access(all) var numberMintedPerItem: {UInt32: UInt32}
199
200 init(name: String, description: String?) {
201 self.setId = TicalUniverse.nextSetId
202 self.items = []
203 self.retired = {}
204 self.locked = false
205 self.numberMintedPerItem = {}
206
207 // Create a new SetData for this Set and store it in contract storage
208 TicalUniverse.setDatas[self.setId] = SetData(name: name, description: description)
209 }
210
211 // Add an Item to the Set
212 //
213 // Pre-Conditions:
214 // The Item exists.
215 // The Set is unlocked.
216 // The Item is not present in the Set.
217 access(all) fun addItem(itemId: UInt32) {
218 pre {
219 TicalUniverse.itemDatas[itemId] != nil: "Cannot add the Item to Set: Item doesn't exist."
220 !self.locked: "Cannot add the Item to the Set after the set has been locked."
221 self.numberMintedPerItem[itemId] == nil: "The Item has already beed added to the set."
222 }
223
224 // Add the Item to the array of Items
225 self.items.append(itemId)
226
227 // Allow minting for Item
228 self.retired[itemId] = false
229
230 // Initialize the Collectible count to zero
231 self.numberMintedPerItem[itemId] = 0
232
233 emit ItemAddedToSet(setId: self.setId, itemId: itemId)
234 }
235
236 // Adds multiple Items to the Set
237 access(all) fun addItems(itemIds: [UInt32]) {
238 for id in itemIds {
239 self.addItem(itemId: id)
240 }
241 }
242
243 // Retire an Item from the Set. The Set can't mint new Collectibles for the Item.
244 // Pre-Conditions:
245 // The Item is part of the Set and not retired.
246 access(all) fun retireItem(itemId: UInt32) {
247 pre {
248 self.retired[itemId] != nil: "Cannot retire the Item: Item doesn't exist in this set!"
249 }
250
251 if !self.retired[itemId]! {
252 self.retired[itemId] = true
253
254 emit ItemRetiredFromSet(setId: self.setId, itemId: itemId, minted: self.numberMintedPerItem[itemId]!)
255 }
256 }
257
258 // Retire all the Items in the Set
259 access(all) fun retireAll() {
260 for id in self.items {
261 self.retireItem(itemId: id)
262 }
263 }
264
265 // Lock the Set so that no more Items can be added to it.
266 //
267 // Pre-Conditions:
268 // The Set is unlocked
269 access(all) fun lock() {
270 if !self.locked {
271 self.locked = true
272 emit SetLocked(setId: self.setId)
273 }
274 }
275
276 // Mint a new Collectible and returns the newly minted Collectible.
277 // Pre-Conditions:
278 // The Item must exist in the Set and be allowed to mint new Collectibles
279 access(all) fun mintCollectible(itemId: UInt32): @NFT {
280 pre {
281 self.retired[itemId] != nil: "Cannot mint the collectible: This item doesn't exist."
282 !self.retired[itemId]!: "Cannot mint the collectible from this item: This item has been retired."
283 }
284
285 // Gets the number of Collectibles that have been minted for this Item
286 // to use as this Collectibles's serial number
287 let minted = self.numberMintedPerItem[itemId]!
288
289 // Mint the new collectible
290 let newCollectible: @NFT <- create NFT(serialNumber: minted + UInt32(1),
291 itemId: itemId,
292 setId: self.setId)
293
294 // Increment the count of Collectibles minted for this Item
295 self.numberMintedPerItem[itemId] = minted + UInt32(1)
296
297 return <-newCollectible
298 }
299
300 // Mint an arbitrary quantity of Collectibles and return them as a Collection
301 access(all) fun batchMintCollectible(itemId: UInt32, quantity: UInt64): @Collection {
302 let newCollection <- create Collection()
303
304 var i: UInt64 = 0
305 while i < quantity {
306 newCollection.deposit(token: <-self.mintCollectible(itemId: itemId))
307 i = i + UInt64(1)
308 }
309
310 return <-newCollection
311 }
312 }
313
314 // Struct of Collectible metadata
315 access(all) struct CollectibleData {
316
317 // The Id of the Set that the Collectible comes from
318 access(all) let setId: UInt32
319
320 // The Id of the Item that the Collectible references
321 access(all) let itemId: UInt32
322
323 // The place in the edition that this Collectible was minted
324 access(all) let serialNumber: UInt32
325
326 init(setId: UInt32, itemId: UInt32, serialNumber: UInt32) {
327 self.setId = setId
328 self.itemId = itemId
329 self.serialNumber = serialNumber
330 }
331
332 }
333
334 // The resource that represents the Collectible NFT
335 access(all) resource NFT: NonFungibleToken.NFT, ViewResolver.Resolver {
336
337 access(all) event ResourceDestroyed(id: UInt64 = self.id)
338
339 // Global unique Collectible Id
340 access(all) let id: UInt64
341
342 // Struct of Collectible metadata
343 access(all) let data: CollectibleData
344
345 init(serialNumber: UInt32, itemId: UInt32, setId: UInt32) {
346
347 // Increment the global Collectible Id
348 TicalUniverse.totalSupply = TicalUniverse.totalSupply + UInt64(1)
349
350 self.id = TicalUniverse.totalSupply
351
352 self.data = CollectibleData(setId: setId, itemId: itemId, serialNumber: serialNumber)
353
354 emit CollectibleMinted(id: self.id, itemId: itemId, setId: setId, serialNumber: self.data.serialNumber)
355 }
356
357
358 access(all) view fun getViews(): [Type] {
359 return [
360 Type<MetadataViews.Royalties>(),
361 Type<MetadataViews.Display>(),
362 Type<MetadataViews.Editions>(),
363 Type<MetadataViews.ExternalURL>(),
364 Type<MetadataViews.NFTCollectionData>(),
365 Type<MetadataViews.NFTCollectionDisplay>(),
366 Type<MetadataViews.Serial>(),
367 Type<MetadataViews.Traits>()
368 ]
369 }
370
371 access(all) fun resolveView(_ view: Type): AnyStruct? {
372 switch view {
373 case Type<MetadataViews.Royalties>():
374 return MetadataViews.Royalties(
375 []
376 )
377 case Type<MetadataViews.Display>():
378 let metadata = TicalUniverse.getItemMetadata(itemId: self.data.itemId)!
379 let assetUrl = metadata["Asset"]!
380 return MetadataViews.Display(
381 name: metadata["Title"]!,
382 description: metadata["Description"]!,
383 thumbnail: MetadataViews.HTTPFile(
384 url: assetUrl.slice(from: 0, upTo: assetUrl.length - 3).concat("gif")
385 )
386 )
387 case Type<MetadataViews.Editions>():
388 let editionInfo = MetadataViews.Edition(name: "Tical Universe", number: self.id, max: nil)
389 let editionList: [MetadataViews.Edition] = [editionInfo]
390 return MetadataViews.Editions(
391 editionList
392 )
393 case Type<MetadataViews.Serial>():
394 return MetadataViews.Serial(
395 self.uuid
396 )
397 case Type<MetadataViews.ExternalURL>():
398 return MetadataViews.ExternalURL("https://www.tunegonft.com/collectible/".concat(self.uuid.toString()))
399 case Type<MetadataViews.NFTCollectionData>():
400 return TicalUniverse.resolveContractView(resourceType: Type<@TicalUniverse.NFT>(), viewType: Type<MetadataViews.NFTCollectionData>())
401 case Type<MetadataViews.NFTCollectionDisplay>():
402 return TicalUniverse.resolveContractView(resourceType: Type<@TicalUniverse.NFT>(), viewType: Type<MetadataViews.NFTCollectionDisplay>())
403 case Type<MetadataViews.Traits>():
404 let metadata = TicalUniverse.getItemMetadata(itemId: self.data.itemId)
405 let traitsView = metadata != nil ? MetadataViews.dictToTraits(dict: metadata!, excludedNames: []) : nil
406 return traitsView
407 }
408 return nil
409 }
410
411 access(all) fun createEmptyCollection(): @{NonFungibleToken.Collection} {
412 return <-TicalUniverse.createEmptyCollection(nftType: Type<@TicalUniverse.NFT>())
413 }
414 }
415
416 // Admin is an authorization resource that allows the owner to modify
417 // various aspects of the Items, Sets, and Collectibles
418 access(all) resource Admin {
419 // Create a new Item struct and store it in the Items dictionary in the contract
420 access(all) fun createItem(metadata: {String: String}): UInt32 {
421 var newItem = Item(metadata: metadata)
422 let newId = newItem.itemId
423
424 TicalUniverse.itemDatas[newId] = newItem
425
426 return newId
427 }
428
429 // Create a new Set resource and store it in the sets mapping in the contract
430 access(all) fun createSet(name: String, description: String?) {
431 var newSet <- create Set(name: name, description: description)
432 TicalUniverse.sets[newSet.setId] <-! newSet
433 }
434
435 // Return a reference to a set in the contract
436 access(all) fun borrowSet(setId: UInt32): &Set {
437 pre {
438 TicalUniverse.sets[setId] != nil: "Cannot borrow set: The set doesn't exist."
439 }
440
441 return (&TicalUniverse.sets[setId] as &Set?)!
442 }
443
444 // End the current series and start a new one
445 access(all) fun startNewSeries(): UInt32 {
446 TicalUniverse.currentSeries = TicalUniverse.currentSeries + UInt32(1)
447
448 emit NewSeriesStarted(newCurrentSeries: TicalUniverse.currentSeries)
449
450 return TicalUniverse.currentSeries
451 }
452
453 // Create a new Admin resource
454 access(all) fun createNewAdmin(): @Admin {
455 return <-create Admin()
456 }
457 }
458
459 // Interface that users can cast their TicalUniverse Collection as
460 // to allow others to deposit TicalUniverse Collectibles into their Collection.
461 access(all) resource interface TicalUniverseCollectionPublic: NonFungibleToken.Receiver, ViewResolver.ResolverCollection {
462 access(all) fun deposit(token: @{NonFungibleToken.NFT})
463 access(all) fun batchDeposit(tokens: @{NonFungibleToken.Collection})
464 access(all) view fun borrowNFT(_ id: UInt64): &{NonFungibleToken.NFT}?
465 access(all) view fun borrowCollectible(_ id: UInt64): &TicalUniverse.NFT? {
466 // If the result isn't nil, the id of the returned reference
467 // should be the same as the argument to the function
468 post {
469 (result == nil) || (result?.id == id):
470 "Cannot borrow collectible reference: The id of the returned reference is incorrect."
471 }
472 }
473 access(all) view fun getSupportedNFTTypes(): {Type: Bool}
474 access(all) view fun isSupportedNFTType(type: Type): Bool
475 }
476
477 // Collection is a resource that every user who owns NFTs
478 // will store in their account to manage their NFTS
479 access(all) resource Collection: NonFungibleToken.Collection, TicalUniverseCollectionPublic, NonFungibleToken.Provider, NonFungibleToken.Receiver, NonFungibleToken.CollectionPublic, ViewResolver.ResolverCollection {
480 access(all) event ResourceDestroyed()
481 // Dictionary of Collectible conforming tokens
482 access(all) var ownedNFTs: @{UInt64: {NonFungibleToken.NFT}}
483
484 init() {
485 self.ownedNFTs <- {}
486 }
487
488 /// getSupportedNFTTypes returns a list of NFT types that this receiver accepts
489 access(all) view fun getSupportedNFTTypes(): {Type: Bool} {
490 let supportedTypes: {Type: Bool} = {}
491 supportedTypes[Type<@TicalUniverse.NFT>()] = true
492 return supportedTypes
493 }
494
495 /// Returns whether or not the given type is accepted by the collection
496 /// A collection that can accept any type should just return true by default
497 access(all) view fun isSupportedNFTType(type: Type): Bool {
498 if type == Type<@TicalUniverse.NFT>() {
499 return true
500 }
501 return false
502 }
503
504 // Remove a Collectible from the Collection and moves it to the caller
505 access(NonFungibleToken.Withdraw) fun withdraw(withdrawID: UInt64): @{NonFungibleToken.NFT} {
506
507 let token <- self.ownedNFTs.remove(key: withdrawID)
508 ?? panic("Cannot withdraw: Collectible does not exist in the collection.")
509
510 emit Withdraw(id: token.id, from: self.owner?.address)
511
512 return <-token
513 }
514
515 // Withdraw multiple tokens and returns them as a Collection
516 access(NonFungibleToken.Withdraw)
517 fun batchWithdraw(ids: [UInt64]): @{NonFungibleToken.Collection} {
518 var batchCollection <- create Collection()
519
520 for id in ids {
521 batchCollection.deposit(token: <-self.withdraw(withdrawID: id))
522 }
523
524 return <-batchCollection
525 }
526
527 // Add a Collectible to the Collections dictionary
528 access(all) fun deposit(token: @{NonFungibleToken.NFT}) {
529
530 // Cast the deposited token as a Collectible NFT to make sure
531 // it is the correct type
532 let token <- token as! @TicalUniverse.NFT
533
534 let id = token.id
535
536 let oldToken <- self.ownedNFTs[id] <- token
537
538 emit Deposit(id: id, to: self.owner?.address)
539
540 // Destroy the empty removed token
541 destroy oldToken
542 }
543
544 // Deposit multiple NFTs into this Collection
545 access(all) fun batchDeposit(tokens: @{NonFungibleToken.Collection}) {
546
547 let keys = tokens.getIDs()
548
549 for key in keys {
550 self.deposit(token: <-tokens.withdraw(withdrawID: key))
551 }
552
553 // Destroy the empty Collection
554 destroy tokens
555 }
556
557 // Get the Ids that are in the Collection
558 access(all) view fun getIDs(): [UInt64] {
559 return self.ownedNFTs.keys
560 }
561
562 // Gets the amount of NFTs stored in the collection
563 access(all) view fun getLength(): Int {
564 return self.ownedNFTs.keys.length
565 }
566
567 // Return a borrowed reference to a Collectible in the Collection
568 // This only allows the caller to read the ID of the NFT,
569 // not any Collectible specific data.
570 access(all) view fun borrowNFT(_ id: UInt64): &{NonFungibleToken.NFT}? {
571 return &self.ownedNFTs[id] as &{NonFungibleToken.NFT}?
572 }
573
574 // Return a borrowed reference to a Collectible
575 // This allows the caller to read the setId, itemId, serialNumber,
576 // and use them to read the setData or Item data from the contract
577 access(all) view fun borrowCollectible(_ id: UInt64): &TicalUniverse.NFT? {
578 if self.ownedNFTs[id] != nil {
579 return (&self.ownedNFTs[id] as &{NonFungibleToken.NFT}? as! &TicalUniverse.NFT?)
580 } else {
581 return nil
582 }
583 }
584
585 access(all) view fun borrowViewResolver(id: UInt64): &{ViewResolver.Resolver}? {
586 if let nft = &self.ownedNFTs[id] as &{NonFungibleToken.NFT}? {
587 return nft as &{ViewResolver.Resolver}
588 }
589 return nil
590 }
591
592 access(all) fun createEmptyCollection(): @{NonFungibleToken.Collection} {
593 return <-create TicalUniverse.Collection()
594 }
595 }
596
597 // -----------------------------------------------------------------------
598 // TicalUniverse contract-level function definitions
599 // -----------------------------------------------------------------------
600
601 // Create a new, empty Collection object so that a user can store it in their account storage
602 // and be able to receive Collectibles
603 access(all) fun createEmptyCollection(nftType: Type): @{NonFungibleToken.Collection} {
604 assert(nftType == Type<@TicalUniverse.NFT>(), message: "I don't know how to create ".concat(nftType.identifier))
605 return <-create TicalUniverse.Collection()
606 }
607
608 access(all) view fun getContractViews(resourceType: Type?): [Type] {
609 return [
610 Type<MetadataViews.NFTCollectionData>(),
611 Type<MetadataViews.NFTCollectionDisplay>()
612 ]
613 }
614
615 access(all) fun resolveContractView(resourceType: Type?, viewType: Type): AnyStruct? {
616 switch viewType {
617 case Type<MetadataViews.NFTCollectionData>():
618 return MetadataViews.NFTCollectionData(
619 storagePath: TicalUniverse.CollectionStoragePath,
620 publicPath: TicalUniverse.CollectionPublicPath,
621 publicCollection: Type<&TicalUniverse.Collection>(),
622 publicLinkedType: Type<&{NonFungibleToken.Collection, TicalUniverse.TicalUniverseCollectionPublic,ViewResolver.ResolverCollection}>(),
623 createEmptyCollectionFunction: (fun(): @{NonFungibleToken.Collection} {
624 return <-TicalUniverse.createEmptyCollection(nftType: Type<@TicalUniverse.NFT>())
625 })
626 )
627 case Type<MetadataViews.NFTCollectionDisplay>():
628 return TicalUniverse.getCollectionDisplay()
629 }
630 return nil
631 }
632
633
634 // Return all the Collectible Items
635 access(all) fun getAllItems(): [TicalUniverse.Item] {
636 return TicalUniverse.itemDatas.values
637 }
638
639 // Get all metadata of an Item
640 access(all) fun getItemMetadata(itemId: UInt32): {String: String}? {
641 return self.itemDatas[itemId]?.metadata
642 }
643
644 // Get a metadata field of an Item
645 access(all) fun getItemMetadataByField(itemId: UInt32, field: String): String? {
646 if let item = TicalUniverse.itemDatas[itemId] {
647 return item.metadata[field]
648 } else {
649 return nil
650 }
651 }
652
653 // Get the name of the Set
654 access(all) fun getSetName(setId: UInt32): String? {
655 return TicalUniverse.setDatas[setId]?.name
656 }
657
658 // Get the description of the Set
659 access(all) fun getSetDescription(setId: UInt32): String? {
660 return TicalUniverse.setDatas[setId]?.description
661 }
662
663 // Get the series that the specified Set is associated with
664 access(all) fun getSetSeries(setId: UInt32): UInt32? {
665 return TicalUniverse.setDatas[setId]?.series
666 }
667
668 // Get the Ids that the specified Set name is associated with
669 access(all) fun getSetIdsByName(setName: String): [UInt32]? {
670 var setIds: [UInt32] = []
671
672 for setData in TicalUniverse.setDatas.values {
673 if setName == setData.name {
674 setIds.append(setData.setId)
675 }
676 }
677
678 if setIds.length == 0 {
679 return nil
680 } else {
681 return setIds
682 }
683 }
684
685 // Get the list of Item Ids that are in the Set
686 access(all) fun getItemsInSet(setId: UInt32): [UInt32]? {
687 return TicalUniverse.sets[setId]?.items
688 }
689
690 // Indicates if a Set/Item combo (otherwise known as an edition) is retired
691 access(all) fun isEditionRetired(setId: UInt32, itemId: UInt32): Bool? {
692 if let setToRead <- TicalUniverse.sets.remove(key: setId) {
693 let retired = setToRead.retired[itemId]
694 TicalUniverse.sets[setId] <-! setToRead
695 return retired
696 } else {
697 return nil
698 }
699 }
700
701 // Indicates if the Set is locked or not
702 access(all) fun isSetLocked(setId: UInt32): Bool? {
703 return TicalUniverse.sets[setId]?.locked
704 }
705
706 // Total number of Collectibles that have been minted from an edition
707 access(all) fun getNumberCollectiblesInEdition(setId: UInt32, itemId: UInt32): UInt32? {
708 if let setToRead <- TicalUniverse.sets.remove(key: setId) {
709 let amount = setToRead.numberMintedPerItem[itemId]
710
711 // Put the Set back into the Sets dictionary
712 TicalUniverse.sets[setId] <-! setToRead
713
714 return amount
715 } else {
716 return nil
717 }
718 }
719
720 access(all) fun getCollectionDisplay(): MetadataViews.NFTCollectionDisplay {
721 let media = MetadataViews.Media(
722 file: MetadataViews.HTTPFile(
723 url: "https://tunegonft.com/assets/images/collections-page/tical.png"
724 ),
725 mediaType: "image/png"
726 )
727 let socials: {String:MetadataViews.ExternalURL} = {}
728 return MetadataViews.NFTCollectionDisplay(
729 name: "Tical Universe",
730 description: "The Genesis NFT drop represents the dawn of Method Man’s Tical Universe and the birth and introduction of the original Tical Universe heroes and villains.",
731 externalURL: MetadataViews.ExternalURL("https://www.tunegonft.com/collection-details/95487a67-a66a-43d5-913d-46fa8a644f4c"),
732 squareImage: media,
733 bannerImage: media,
734 socials: socials
735 )
736 }
737
738 // -----------------------------------------------------------------------
739 // TicalUniverse initialization function
740 // -----------------------------------------------------------------------
741
742 init() {
743 // Paths
744 self.CollectionPublicPath= /public/TicalUniverseCollection
745 self.CollectionStoragePath= /storage/TicalUniverseCollection
746 self.AdminPublicPath= /public/TicalUniverseAdmin
747 self.AdminStoragePath=/storage/TicalUniverseAdmin
748
749 self.currentSeries = 0
750 self.itemDatas = {}
751 self.setDatas = {}
752 self.sets <- {}
753 self.nextItemId = 1
754 self.nextSetId = 1
755 self.totalSupply = 0
756
757 // Put a new Collection in storage
758 self.account.storage.save(<- create Collection(), to: TicalUniverse.CollectionStoragePath)
759
760 // create a public capability for the collection
761 let collectionCap = self.account.capabilities.storage.issue<&TicalUniverse.Collection>(TicalUniverse.CollectionStoragePath)
762 self.account.capabilities.publish(collectionCap, at: TicalUniverse.CollectionPublicPath)
763
764 // Put the Admin in storage
765 self.account.storage.save(<- create Admin(), to: TicalUniverse.AdminStoragePath)
766
767 emit ContractInitialized()
768 }
769}