Smart Contract

FlowversePass

A.9212a87501a8a6a2.FlowversePass

Deployed

2d ago
Feb 26, 2026, 12:24:04 AM UTC

Dependents

3453 imports
1/*
2    FlowversePass.cdc
3
4    Author: Brian Min brian@flowverse.co
5*/
6
7import NonFungibleToken from 0x1d7e57aa55817448
8import MetadataViews from 0x1d7e57aa55817448
9import FungibleToken from 0xf233dcee88fe0abe
10import ViewResolver from 0x1d7e57aa55817448
11
12access(all) contract FlowversePass: NonFungibleToken {
13    // Events
14    access(all) event EntityCreated(id: UInt64, metadata: {String:String})
15    access(all) event EntityUpdated(id: UInt64, metadata: {String:String})
16    access(all) event SetCreated(setID: UInt64, name: String, description: String, externalURL: String, isPrivate: Bool, imageIPFS: String)
17    access(all) event SetUpdated(setID: UInt64, description: String?, externalURL: String?, imageIPFS: String?)
18    access(all) event EntityAddedToSet(setID: UInt64, entityID: UInt64)
19    access(all) event EntityRetiredFromSet(setID: UInt64, entityID: UInt64, numNFTs: UInt64)
20    access(all) event SetLocked(setID: UInt64)
21    access(all) event NFTMinted(nftID: UInt64, nftUUID: UInt64, entityID: UInt64, setID: UInt64, mintNumber: UInt64, minterAddress: Address)
22
23    // Named Paths
24    access(all) let CollectionStoragePath: StoragePath
25    access(all) let CollectionPublicPath: PublicPath
26    access(all) let AdminStoragePath: StoragePath
27
28    access(self) var entityDatas: {UInt64: Entity}
29    access(self) var setDatas: {UInt64: SetData}
30    access(self) var sets: @{UInt64: Set}
31
32    // Total number of FlowversePass NFTs that have been minted
33    access(all) var totalSupply: UInt64
34
35    // Incremented ID used to create entities
36    access(all) var nextEntityID: UInt64
37
38    // Incremented ID used to create sets
39    access(all) var nextSetID: UInt64
40
41    // Entity is a Struct that holds metadata associated 
42    // with an NFT entity
43    // NFTs will all reference a single entity as the owner of
44    // its metadata. The entities are publicly accessible, so anyone can
45    // read the metadata associated with a specific entity ID
46    access(all) struct Entity {
47        // Unique ID for the entity
48        access(all) let entityID: UInt64
49
50        // Stores all the metadata about the entity as a string mapping
51        access(all) var metadata: {String: String}
52
53        init(metadata: {String: String}) {
54            pre {
55                metadata.length != 0: "New Entity metadata cannot be empty"
56            }
57            self.entityID = FlowversePass.nextEntityID
58            self.metadata = metadata
59        }
60    }
61
62    // A Set is a group of Entities, like a group of collectibles.
63    // An Entity can exist in multiple different sets. 
64    // SetData is a struct that is stored in a field of the contract.
65    access(all) struct SetData {
66
67        // Unique ID for the Set
68        access(all) let setID: UInt64
69
70        // Name of the Set
71        access(all) let name: String
72
73        // Description of the Set
74        access(all) let description: String
75
76        // externalURL of the Set
77        access(all) let externalURL: String
78
79        // Image of the Set
80        access(all) let imageIPFS: String
81
82        // Indicates if this Set is listed / available to public
83        // e.g. admin may create a private collection for air dropping nfts
84        access(all) var isPrivate: Bool
85
86        init(setID: UInt64, name: String, description: String, externalURL: String, imageIPFS: String, isPrivate: Bool) {
87            pre {
88                name.length > 0: "New set name cannot be empty"
89                description.length > 0: "New set description cannot be empty"
90                imageIPFS.length > 0: "New set imageIPFS cannot be empty"
91            }
92
93            self.setID = setID
94            self.name = name
95            self.description = description
96            self.externalURL = externalURL
97            self.imageIPFS = imageIPFS
98            self.isPrivate = isPrivate
99        }
100    }
101
102    // Set is a resource type that contains the functions to add and remove
103    // Entities from a set and mint NFTs.
104    //
105    // It is stored in a private field in the contract so that
106    // the admin resource can call its methods.
107    //
108    // The admin can add Entitys to a Set so that the set can mint NFTs
109    // that reference that entity data.
110    // The NFTs that are minted by a Set will be listed as belonging to
111    // the Set that minted it, as well as the Entity it references.
112    // 
113    // Admin can also lock Entitys from the Set, meaning that the locked
114    // Entity can no longer have NFTs minted from it.
115    //
116    // If the admin locks the Set, no more Entitys can be added to it, but 
117    // NFTs can still be minted.
118    //
119    // If lockAll() and lock() are called back-to-back, 
120    // the Set is closed off forever and nothing more can be done with it.
121    access(all) resource Set {
122
123        // Unique ID for the set
124        access(all) let setID: UInt64
125
126        // Array of entities that are a part of this set.
127        // When a entity is added to the set, its ID gets appended here.
128        // The ID does not get removed from this array when a entities is locked.
129        access(self) var entities: [UInt64]
130
131        // Map of entity IDs that Indicates if a entity in this Set can be minted.
132        // When a entities is added to a Set, it is mapped to false (not locked).
133        // When a entity is retired, this is set to true and cannot be changed.
134        access(self) var retired: {UInt64: Bool}
135
136        // Indicates if the Set is currently locked.
137        // When a Set is created, it is unlocked 
138        // and entities are allowed to be added to it.
139        // When a set is locked, entities cannot be added.
140        // A Set can never be changed from locked to unlocked,
141        // the decision to lock a Set it is final.
142        // If a Set is locked, entities cannot be added, but
143        // NFTs can still be minted from entities
144        // that exist in the Set.
145        access(all) var locked: Bool
146
147        // Mapping of Entity IDs that indicates the number of NFTs 
148        // that have been minted for specific Entitys in this Set.
149        // When a NFT is minted, this value is stored in the NFT to
150        // show its place in the Set, eg. 13 of 60.
151        access(self) var numMintedPerEntity: {UInt64: UInt64}
152
153        access(all) var totalMinted: UInt64
154
155        init()
156         {
157            self.setID = FlowversePass.nextSetID
158            self.entities = []
159            self.retired = {}
160            self.locked = false
161            self.numMintedPerEntity = {}
162            self.totalMinted = 0
163        }
164
165        // addEntity adds an entity to the set
166        //
167        // Parameters: entityID: The ID of the entity that is being added
168        //
169        // Pre-Conditions:
170        // The entity needs to be an existing entity
171        // The Set needs to be not locked
172        // The entity can't have already been added to the Set
173        //
174        access(all) fun addEntity(entityID: UInt64) {
175            pre {
176                FlowversePass.entityDatas[entityID] != nil: "Cannot add the Entity to Set: Entity doesn't exist."
177                !self.locked: "Cannot add the entity to the Set after the set has been locked."
178                self.numMintedPerEntity[entityID] == nil: "The entity has already been added to the set."
179            }
180
181            // Add the Entity to the array of Plays
182            self.entities.append(entityID)
183
184            // Open the Entity up for minting
185            self.retired[entityID] = false
186
187            // Initialize the Entity count to zero
188            self.numMintedPerEntity[entityID] = 0
189
190            emit EntityAddedToSet(setID: self.setID, entityID: entityID)
191        }
192
193        // addEntities adds multiple entities to the Set
194        //
195        // Parameters: entityIDs: The IDs of the entities that are being added
196        //
197        access(all) fun addEntities(entityIDs: [UInt64]) {
198            for entity in entityIDs {
199                self.addEntity(entityID: entity)
200            }
201        }
202
203        // retireEntity retires a Entity from the Set so that it can't mint new NFTs
204        //
205        // Parameters: entityID: The ID of the Entity that is being retired
206        //
207        // Pre-Conditions:
208        // The Entity is part of the Set and not retired (available for minting).
209        // 
210        access(all) fun retireEntity(entityID: UInt64) {
211            pre {
212                self.retired[entityID] != nil: "Cannot retire the entity: Entity doesn't exist in this set!"
213            }
214
215            if !self.retired[entityID]! {
216                self.retired[entityID] = true
217
218                emit EntityRetiredFromSet(setID: self.setID, entityID: entityID, numNFTs: self.numMintedPerEntity[entityID]!)
219            }
220        }
221
222        // retireAll retires all the entities in the Set
223        // Afterwards, none of the retired entities will be able to mint new instances
224        //
225        access(all) fun retireAll() {
226            for entity in self.entities {
227                self.retireEntity(entityID: entity)
228            }
229        }
230
231        // lock() locks the Set so that no more Entitys can be added to it
232        //
233        // Pre-Conditions:
234        // The Set should not be locked
235        access(all) fun lock() {
236            if !self.locked {
237                self.locked = true
238                emit SetLocked(setID: self.setID)
239            }
240        }
241
242        // mint mints a new entity instance and returns the newly minted instance of an entity
243        // 
244        // Parameters: 
245        // entityID: The ID of the Entity that the NFT references
246        // minterAddress: The address of the minter
247        //
248        // Pre-Conditions:
249        // The Entity must exist in the Set and be allowed to mint new NFTs
250        //
251        // Returns: The NFT that was minted
252        // 
253        access(all) fun mint(entityID: UInt64, minterAddress: Address): @NFT {
254            pre {
255                self.retired[entityID] != nil: "Cannot mint: the entity doesn't exist."
256                !self.retired[entityID]!: "Cannot mint from this entity: the entity has been retired."
257            }
258
259            // Gets the number of NFTs that have been minted for this Entity
260            // to use as this NFT's serial number
261            let numInEntity = self.numMintedPerEntity[entityID]!
262
263            // Mint the new NFT
264            let newNFT: @NFT <- create NFT(mintNumber: numInEntity + UInt64(1),
265                                              entityID: entityID,
266                                              setID: self.setID,
267                                              minterAddress: minterAddress)
268
269            // Increment the number of copies minted for this NFT
270            self.numMintedPerEntity[entityID] = numInEntity + UInt64(1)
271
272            self.totalMinted = self.totalMinted + UInt64(1)
273
274            return <-newNFT
275        }
276
277        access(all) view fun getEntities(): [UInt64] {
278            return self.entities
279        }
280
281        access(all) view fun getRetired(): {UInt64: Bool} {
282            return self.retired
283        }
284
285        access(all) view fun getNumMintedPerEntity(): {UInt64: UInt64} {
286            return self.numMintedPerEntity
287        }
288
289        access(all) view fun getTotalMinted(): UInt64 {
290            return self.totalMinted
291        }
292    }
293
294    // Struct that contains all of the important data about a set
295    // Can be easily queried by instantiating the `QuerySetData` object
296    // with the desired set ID
297    // let setData = FlowversePass.QuerySetData(setID: 12)
298    //
299    access(all) struct QuerySetData {
300        access(all) let setID: UInt64
301        access(all) let name: String
302        access(all) let description: String
303        access(all) let externalURL: String
304        access(all) let imageIPFS: String
305        access(all) let isPrivate: Bool
306        access(self) var entities: [UInt64]
307        access(self) var retired: {UInt64: Bool}
308        access(all) var locked: Bool
309        access(self) var numMintedPerEntity: {UInt64: UInt64}
310        access(all) var totalMinted: UInt64
311
312        init(setID: UInt64) {
313            pre {
314                FlowversePass.sets[setID] != nil: "The set with the provided ID does not exist"
315            }
316
317            let set = (&FlowversePass.sets[setID] as &Set?)!
318            let setData = FlowversePass.setDatas[setID]!
319
320            self.setID = setID
321            self.name = setData.name
322            self.description = setData.description
323            self.externalURL = setData.externalURL
324            self.imageIPFS = setData.imageIPFS
325            self.entities = set.getEntities()
326            self.retired = set.getRetired()
327            self.locked = set.locked
328            self.numMintedPerEntity = set.getNumMintedPerEntity()
329            self.totalMinted = set.getTotalMinted()
330            self.isPrivate = setData.isPrivate
331        }
332
333        access(all) view fun getEntities(): [UInt64] {
334            return self.entities
335        }
336
337        access(all) view fun getRetired(): {UInt64: Bool} {
338            return self.retired
339        }
340
341        access(all) view fun getNumMintedPerEntity(): {UInt64: UInt64} {
342            return self.numMintedPerEntity
343        }
344    }
345
346    // NFT Resource that represents the Entity instances
347    access(all) resource NFT: NonFungibleToken.NFT, ViewResolver.Resolver {
348        // Global unique NFT ID
349        access(all) let id: UInt64
350
351        // The ID of the Set that the NFT comes from
352        access(all) let setID: UInt64
353
354        // The ID of the Entity that the NFT references
355        access(all) let entityID: UInt64
356
357        // The minterAddress of the NFT
358        access(all) let minterAddress: Address
359
360        // The serial number of the NFT, number minted for this entity in the set
361        access(all) let mintNumber: UInt64
362
363        init(mintNumber: UInt64, entityID: UInt64, setID: UInt64, minterAddress: Address) {
364            // Increment the global NFT ID
365            FlowversePass.totalSupply = FlowversePass.totalSupply + UInt64(1)
366
367            self.id = FlowversePass.totalSupply
368
369            self.mintNumber = mintNumber
370            self.entityID = entityID
371            self.setID = setID
372            self.minterAddress = minterAddress
373
374            emit NFTMinted(nftID: self.id, nftUUID: self.uuid, entityID: entityID, setID: self.setID, mintNumber: self.mintNumber, minterAddress: self.minterAddress)
375        }
376
377        access(all) view fun name(): String {
378            let name: String = FlowversePass.getEntityMetaDataByField(entityID: self.entityID, field: "name") ?? ""
379            return name.concat(" #").concat(self.mintNumber.toString())
380        }
381
382        access(all) view fun getViews(): [Type] {
383            return [
384                Type<MetadataViews.Display>(),
385                Type<MetadataViews.Royalties>(),
386                Type<MetadataViews.Serial>(),
387                Type<MetadataViews.Edition>(),
388                Type<MetadataViews.ExternalURL>(),
389                Type<MetadataViews.Medias>()
390            ]
391        }
392
393        access(all) view fun resolveView(_ view: Type): AnyStruct? {
394            let fileExtension = FlowversePass.getEntityMetaDataByField(entityID: self.entityID, field: "fileExtension") ?? ""
395            switch view {
396                case Type<MetadataViews.Display>():
397                    return MetadataViews.Display(
398                        name: self.name(),
399                        description: FlowversePass.getEntityMetaDataByField(entityID: self.entityID, field: "description") ?? "",
400                        thumbnail: MetadataViews.HTTPFile(url: "https://flowverse-mystery-pass.s3.filebase.com/mainnet/nft_thumbnail.gif")
401                    )
402                case Type<MetadataViews.Royalties>():
403                    let feeReceiverAddress: Address = 0x604b63bcbef5974f
404                    let feeCut: UFix64 = 0.05
405                    let royalties : [MetadataViews.Royalty] = [
406                        MetadataViews.Royalty(
407                            receiver: getAccount(feeReceiverAddress).capabilities.get<&{FungibleToken.Receiver}>(/public/flowTokenReceiver)!,
408                            cut: feeCut,
409                            description: "Creator Royalty Fee")
410                    ]
411                    return MetadataViews.Royalties(royalties)
412                case Type<MetadataViews.Serial>():
413                    return MetadataViews.Serial(self.mintNumber)
414                case Type<MetadataViews.Edition>():
415                    return MetadataViews.Edition(
416                        name: FlowversePass.getEntityMetaDataByField(entityID: self.entityID, field: "name") ?? "",
417                        number: self.mintNumber,
418                        max: 1111
419                    )
420                case Type<MetadataViews.ExternalURL>():
421                    let baseURL = "https://nft.flowverse.co/collections/FlowversePass/"
422                    return MetadataViews.ExternalURL(baseURL.concat(self.owner!.address.toString()).concat("/".concat(self.id.toString())))
423                case Type<MetadataViews.Medias>():
424                    let video = MetadataViews.Media(
425                        file: MetadataViews.HTTPFile(
426                            url: "https://flowverse-mystery-pass.s3.filebase.com/mainnet/nft.".concat(fileExtension)
427                        ),
428                        mediaType: "video/".concat(fileExtension)
429                    )
430                    let medias: [MetadataViews.Media] = [video]
431                    return MetadataViews.Medias(medias)
432            }
433
434            return nil
435        }
436
437        access(all) fun createEmptyCollection(): @{NonFungibleToken.Collection} {
438            return <- FlowversePass.createEmptyCollection(nftType: Type<@FlowversePass.NFT>())
439        }
440    }
441
442    access(all) resource SetMinter {
443        access(all) let setID: UInt64
444
445        init(setID: UInt64) {
446            self.setID = setID
447        }
448
449        access(all) fun mint(entityID: UInt64, minterAddress: Address): @NFT {
450            let setRef = (&FlowversePass.sets[self.setID] as &Set?)!
451            return <- setRef.mint(entityID: entityID, minterAddress: minterAddress)
452        }
453    }
454
455    // Admin is a special authorization resource that 
456    // allows the owner to perform important functions to modify the 
457    // various aspects of the Entities, Sets, and NFTs
458    //
459    access(all) resource Admin {
460
461        // createEntity creates a new Entity struct 
462        // and stores it in the Entities dictionary in the FlowversePass smart contract
463        access(all) fun createEntity(metadata: {String: String}): UInt64 {
464            // Create the new Entity
465            var newEntity = Entity(metadata: metadata)
466            let newID = newEntity.entityID
467
468            // Increment the ID so that it isn't used again
469            FlowversePass.nextEntityID = FlowversePass.nextEntityID + UInt64(1)
470
471            // Store it in the contract storage
472            FlowversePass.entityDatas[newID] = newEntity
473            
474            emit EntityCreated(id: newID, metadata: metadata)
475
476            return newID
477        }
478
479        // createSet creates a new Set resource and stores it
480        // in the sets mapping in the contract
481        access(all) fun createSet(name: String, description: String, externalURL: String, imageIPFS: String, isPrivate: Bool): UInt64 {
482            // Create a new SetData for this Set
483            let setData = SetData(
484                setID: FlowversePass.nextSetID,
485                name: name,
486                description: description,
487                externalURL: externalURL,
488                imageIPFS: imageIPFS,
489                isPrivate: isPrivate
490            )
491
492            // Create the new Set
493            var newSet <- create Set()
494
495             // Increment the setID so that it isn't used again
496            FlowversePass.nextSetID = FlowversePass.nextSetID + UInt64(1)
497            
498            let newID = newSet.setID
499
500            emit SetCreated(setID: newID, name: name, description: description, externalURL: externalURL, isPrivate: isPrivate, imageIPFS: imageIPFS)
501
502            // Store in contract storage
503            FlowversePass.setDatas[newID] = setData
504            FlowversePass.sets[newID] <-! newSet
505
506            return newID
507        }
508        
509        // updateSetData updates set info including: description, externalURL, imageIPFS
510        access(all) fun updateSetData(setID: UInt64, description: String?, externalURL: String?, imageIPFS: String?) {
511            pre {
512                FlowversePass.setDatas.containsKey(setID): "Set data does not exist"
513                FlowversePass.sets.containsKey(setID): "Set data does not exist"
514                FlowversePass.sets[setID]?.locked == false: "Locked set data cannot be updated"
515            }
516            var setData = FlowversePass.setDatas[setID]!
517            let updatedSetData = SetData(
518                setID: setID,
519                name: setData.name,
520                description: description ?? setData.description,
521                externalURL: externalURL ?? setData.externalURL,
522                imageIPFS: imageIPFS ?? setData.imageIPFS,
523                isPrivate: setData.isPrivate
524            )
525            FlowversePass.setDatas[setID] = updatedSetData
526            emit SetUpdated(setID: setID, description: description, externalURL: externalURL, imageIPFS: imageIPFS)
527        }
528
529        // borrowSet returns a reference to a set in the contract
530        // so that the admin can call methods on it
531        access(all) view fun borrowSet(setID: UInt64): &Set {
532            pre {
533                FlowversePass.sets[setID] != nil: "Cannot borrow Set: The Set doesn't exist"
534            }
535            
536            // Get a reference to the Set and return it
537            // use `&` to indicate the reference to the object and type
538            return (&FlowversePass.sets[setID] as &Set?)!
539        }
540
541        access(all) fun createSetMinter(setID: UInt64): @SetMinter {
542            return <- create SetMinter(setID: setID)
543        }
544
545        // createNewAdmin creates a new Admin resource
546        access(all) fun createNewAdmin(): @Admin {
547            return <-create Admin()
548        }
549    }
550
551    // Public interface for the FlowversePass Collection that allows users access to certain functionalities
552    access(all) resource interface CollectionPublic {
553        access(all) fun deposit(token: @{NonFungibleToken.NFT})
554        access(all) view fun getIDs(): [UInt64]
555        access(all) view fun borrowNFT(_ id: UInt64): &{NonFungibleToken.NFT}?
556        access(all) view fun borrowViewResolver(id: UInt64): &{ViewResolver.Resolver}?
557    }
558    
559    // Collection
560    // A collection of FlowversePass NFTs owned by an account
561    access(all) resource Collection: CollectionPublic, NonFungibleToken.Collection {
562        // Dictionary of entity instances conforming tokens
563        // NFT is a resource type with a UInt64 ID field
564        access(all) var ownedNFTs: @{UInt64: {NonFungibleToken.NFT}}
565
566        init () {
567            self.ownedNFTs <- {}
568        }
569
570        /// getSupportedNFTTypes returns a list of NFT types that this receiver accepts
571        access(all) view fun getSupportedNFTTypes(): {Type: Bool} {
572            let supportedTypes: {Type: Bool} = {}
573            supportedTypes[Type<@FlowversePass.NFT>()] = true
574            return supportedTypes
575        }
576
577        /// Returns whether or not the given type is accepted by the collection
578        /// A collection that can accept any type should just return true by default
579        access(all) view fun isSupportedNFTType(type: Type): Bool {
580           if type == Type<@FlowversePass.NFT>() {
581            return true
582           } else {
583            return false
584           }
585        }
586
587        /// Gets the amount of NFTs stored in the collection
588        access(all) view fun getLength(): Int {
589            return self.ownedNFTs.keys.length
590        }
591
592        /// Allows a given function to iterate through the list
593        /// of owned NFT IDs in a collection without first
594        /// having to load the entire list into memory
595        access(all) fun forEachID(_ f: fun (UInt64): Bool): Void {
596            self.ownedNFTs.forEachKey(f)
597        }
598
599        /// deposit takes a NFT and adds it to the collections dictionary
600        /// and adds the ID to the id array
601        access(all) fun deposit(token: @{NonFungibleToken.NFT}) {
602            let token <- token as! @FlowversePass.NFT
603            let id = token.id
604
605            // add the new token to the dictionary which removes the old one
606            let oldToken <- self.ownedNFTs[token.id] <- token
607
608            destroy oldToken
609        }
610
611        access(all) view fun getIDs(): [UInt64] {
612            return self.ownedNFTs.keys
613        }
614
615        access(all) view fun borrowNFT(_ id: UInt64): &{NonFungibleToken.NFT}? {
616            return (&self.ownedNFTs[id] as &{NonFungibleToken.NFT}?)
617        }
618
619        /// Borrow the view resolver for the specified NFT ID
620        access(all) view fun borrowViewResolver(id: UInt64): &{ViewResolver.Resolver}? {
621            if let nft = &self.ownedNFTs[id] as &{NonFungibleToken.NFT}? {
622                return nft as &{ViewResolver.Resolver}
623            }
624            return nil
625        }
626
627        /// createEmptyCollection creates an empty Collection of the same type
628        /// and returns it to the caller
629        /// @return A an empty collection of the same type
630        access(all) fun createEmptyCollection(): @{NonFungibleToken.Collection} {
631            return <-FlowversePass.createEmptyCollection(nftType: Type<@FlowversePass.NFT>())
632        }
633        
634        /// withdraw removes an NFT from the collection and moves it to the caller
635        access(NonFungibleToken.Withdraw) fun withdraw(withdrawID: UInt64): @{NonFungibleToken.NFT} {
636            let token <- self.ownedNFTs.remove(key: withdrawID)
637                ?? panic("Could not withdraw an NFT with the provided ID from the collection")
638
639            return <-token
640        }
641    }
642
643    // -----------------------------------------------------------------------
644    // FlowversePass contract-level function definitions
645    // -----------------------------------------------------------------------
646
647    /// createEmptyCollection creates an empty Collection for the specified NFT type
648    /// and returns it to the caller so that they can own NFTs
649    access(all) fun createEmptyCollection(nftType: Type): @{NonFungibleToken.Collection} {
650        return <- create Collection()
651    }
652
653    /// Function that returns all the Metadata Views implemented by a Non Fungible Token
654    ///
655    /// @return An array of Types defining the implemented views. This value will be used by
656    ///         developers to know which parameter to pass to the resolveView() method.
657    ///
658    access(all) view fun getContractViews(resourceType: Type?): [Type] {
659        return [
660            Type<MetadataViews.NFTCollectionData>(),
661            Type<MetadataViews.NFTCollectionDisplay>()
662        ]
663    }
664
665    /// Function that resolves a metadata view for this contract.
666    ///
667    /// @param view: The Type of the desired view.
668    /// @return A structure representing the requested view.
669    ///
670    access(all) fun resolveContractView(resourceType: Type?, viewType: Type): AnyStruct? {
671        switch viewType {
672           case Type<MetadataViews.NFTCollectionData>():
673                return MetadataViews.NFTCollectionData(
674                    storagePath: self.CollectionStoragePath,
675                    publicPath: self.CollectionPublicPath,
676                    publicCollection: Type<&FlowversePass.Collection>(),
677                    publicLinkedType: Type<&FlowversePass.Collection>(),
678                    createEmptyCollectionFunction: (fun(): @{NonFungibleToken.Collection} {return <- FlowversePass.createEmptyCollection(nftType: Type<@FlowversePass.NFT>())}),
679                )
680            case Type<MetadataViews.NFTCollectionDisplay>():
681                let squareImage = MetadataViews.Media(
682                    file: MetadataViews.HTTPFile(
683                        url: "https://flowverse-mystery-pass.s3.filebase.com/mainnet/squareImage.jpg"
684                    ),
685                    mediaType: "image/jpg"
686                )
687                let bannerImage = MetadataViews.Media(
688                    file: MetadataViews.HTTPFile(
689                        url: "https://flowverse-mystery-pass.s3.filebase.com/mainnet/bannerImage.jpg"
690                    ),
691                    mediaType: "image/jpg"
692                )
693                return MetadataViews.NFTCollectionDisplay(
694                    name: "Flowverse Mystery Pass",
695                    description: "The Flowverse Mystery Pass is a utility-focused membership pass that aims to level up Flowverse from a web2 information provider to a web3 brand",
696                    externalURL: MetadataViews.ExternalURL("https://nft.flowverse.co/flowverse-mystery-pass"),
697                    squareImage: squareImage,
698                    bannerImage: bannerImage,
699                    socials: {
700                        "discord": MetadataViews.ExternalURL("https://discord.gg/flowverse"),
701                        "twitter": MetadataViews.ExternalURL("https://twitter.com/flowverse_"),
702                        "instagram": MetadataViews.ExternalURL("https://www.instagram.com/flowverseofficial")
703                    }
704                )
705        }
706        return nil
707    }
708
709    // getAllEntities returns all the entities available
710    access(all) view fun getAllEntities(): [FlowversePass.Entity] {
711        return FlowversePass.entityDatas.values
712    }
713
714    // getEntity returns an entity by ID
715    access(all) view fun getEntity(entityID: UInt64): FlowversePass.Entity? {
716        return self.entityDatas[entityID]
717    }
718
719    // getEntityMetaData returns all the metadata associated with a specific Entity
720    access(all) view fun getEntityMetaData(entityID: UInt64): {String: String}? {
721        return self.entityDatas[entityID]?.metadata
722    }
723    
724    access(all) view fun getEntityMetaDataByField(entityID: UInt64, field: String): String? {
725        if let entity = FlowversePass.entityDatas[entityID] {
726            return entity.metadata[field]
727        } else {
728            return nil
729        }
730    }
731
732
733    // getSetData returns the data that the specified Set
734    //            is associated with.
735    // 
736    // Parameters: setID: The id of the Set that is being searched
737    //
738    // Returns: The QuerySetData struct that has all the important information about the set
739    access(all) fun getSetData(setID: UInt64): QuerySetData? {
740        if FlowversePass.sets[setID] == nil {
741            return nil
742        } else {
743            return QuerySetData(setID: setID)
744        }
745    }
746    
747    // getSetName returns the name that the specified Set
748    //            is associated with.
749    // 
750    // Parameters: setID: The id of the Set that is being searched
751    //
752    // Returns: The name of the Set
753    access(all) view fun getSetName(setID: UInt64): String? {
754        // Don't force a revert if the setID is invalid
755        return FlowversePass.setDatas[setID]?.name
756    }
757
758    // getSetIDsByName returns the IDs that the specified Set name
759    //                 is associated with.
760    access(all) fun getSetIDsByName(setName: String): [UInt64]? {
761        var setIDs: [UInt64] = []
762
763        for setData in FlowversePass.setDatas.values {
764            if setName == setData.name {
765                setIDs.append(setData.setID)
766            }
767        }
768
769        if setIDs.length == 0 {
770            return nil
771        } else {
772            return setIDs
773        }
774    }
775
776    // getAllSetDatas returns all the set datas available
777    access(all) view fun getAllSetDatas(): [SetData] {
778        return FlowversePass.setDatas.values
779    }
780
781    // getEntitiesInSet returns the list of Entity IDs that are in the Set
782    access(all) view fun getEntitiesInSet(setID: UInt64): [UInt64]? {
783        return FlowversePass.sets[setID]?.getEntities()
784    }
785
786    // isSetEntityRetired returns a boolean that indicates if a Set/Entity combination
787    //                  is retired.
788    //                  If an entity is retired, it still remains in the Set,
789    //                  but NFTs can no longer be minted from it.
790    access(all) fun isSetEntityRetired(setID: UInt64, entityID: UInt64): Bool? {
791        if let setdata = self.getSetData(setID: setID) {
792            // See if the Entity is retired from this Set
793            let retired = setdata.getRetired()[entityID]
794
795            // Return the retired status
796            return retired
797        } else {
798            // If the Set wasn't found, return nil
799            return nil
800        }
801    }
802
803    access(all) view fun isSetLocked(setID: UInt64): Bool? {
804        return FlowversePass.sets[setID]?.locked
805    }
806
807    // getNumInstancesOfEntity return the number of entity instances that have been 
808    //                        minted in a set.
809    //
810    // Parameters: setID: The id of the Set that is being searched
811    //             entityID: The id of the Entity that is being searched
812    //
813    // Returns: The total number of entity instances (NFTs) 
814    //          that have been minted in a set
815    access(all) fun getNumInstancesOfEntity(setID: UInt64, entityID: UInt64): UInt64? {
816        if let setdata = self.getSetData(setID: setID) {
817            // return numMintedPerEntity
818            return setdata.getNumMintedPerEntity()[entityID]
819        } else {
820            // If the set wasn't found return nil
821            return nil
822        }
823    }
824
825    // -----------------------------------------------------------------------
826    // FlowversePass initialization function
827    // -----------------------------------------------------------------------
828    //
829    init() {
830        self.AdminStoragePath = /storage/FlowversePassAdmin
831        self.CollectionStoragePath = /storage/FlowversePassCollection
832        self.CollectionPublicPath = /public/FlowversePassCollection
833
834        // Initialize contract fields
835        self.entityDatas = {}
836        self.setDatas = {}
837        self.sets <- {}
838        self.nextEntityID = 1
839        self.nextSetID = 1
840        self.totalSupply = 0
841
842        // Create and save a new Collection in storage
843        let collection <- create Collection()
844        self.account.storage.save(<-collection, to: self.CollectionStoragePath)
845
846        // Issue a public capability for the Collection
847        let collectionCap = self.account.capabilities.storage.issue<&FlowversePass.Collection>(self.CollectionStoragePath)
848        self.account.capabilities.publish(collectionCap, at: self.CollectionPublicPath)
849
850        // Create and save Admin resource in storage
851        self.account.storage.save<@Admin>(<- create Admin(), to: self.AdminStoragePath)
852    }
853}
854