Smart Contract

TuneGO

A.0d9bc5af3fc0c2e3.TuneGO

Deployed

4d ago
Feb 23, 2026, 01:04:01 AM UTC

Dependents

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