Smart Contract

UFC_NFT

A.329feb3ab062d289.UFC_NFT

Valid From

85,999,254

Deployed

2w ago
Feb 11, 2026, 05:41:35 PM UTC

Dependents

3707 imports
1import Burner from 0xf233dcee88fe0abe
2import FungibleToken from 0xf233dcee88fe0abe
3import NonFungibleToken from 0x1d7e57aa55817448
4import MetadataViews from 0x1d7e57aa55817448
5import ViewResolver from 0x1d7e57aa55817448
6
7access(all) contract UFC_NFT: NonFungibleToken {
8
9    // An entitlement to perform Admin actions on this contract
10    access(all) entitlement Administrator
11
12    // UFC_NFT Events
13    //
14
15    // Emitted when an NFT is minted
16    access(all) event Minted(id: UInt64, setId: UInt32, seriesId: UInt32)
17
18    // Events for Series-related actions
19    //
20    // Emitted when a new Series is created
21    access(all) event SeriesCreated(seriesId: UInt32)
22    // Emitted when a Series is sealed, meaning Series metadata
23    // cannot be updated
24    access(all) event SeriesSealed(seriesId: UInt32)
25    // Emitted when a Series' metadata is updated
26    access(all) event SeriesMetadataUpdated(seriesId: UInt32)
27
28    // NFT Withdraw, Deposit, and Burn Events
29    access(all) event Withdraw(id: UInt64, from: Address?)
30    access(all) event Deposit(id: UInt64, to: Address?)
31    access(all) event NFTDestroyed(id: UInt64)
32
33    // Events for Set-related actions
34    //
35    // Emitted when a new Set is created
36    access(all) event SetCreated(seriesId: UInt32, setId: UInt32)
37    // Emitted when a Set's metadata is updated
38    access(all) event SetMetadataUpdated(seriesId: UInt32, setId: UInt32)
39
40    // Named Paths
41    //
42    access(all) let CollectionStoragePath: StoragePath
43    access(all) let CollectionPublicPath: PublicPath
44    access(all) let AdminStoragePath: StoragePath
45
46    // Variable size dictionary of SetData structs
47    access(self) var setData: {UInt32: NFTSetData}
48
49    // Variable size dictionary of SeriesData structs
50    access(self) var seriesData: {UInt32: SeriesData}
51
52    // Variable size dictionary of Series resources
53    access(self) var series: @{UInt32: Series}
54
55
56    // An NFTSetData is a Struct that holds metadata associated with
57    // a specific NFT Set.
58    access(all) struct NFTSetData {
59
60        // Unique ID for the Set
61        access(all) let setId: UInt32
62
63        // Series ID the Set belongs to
64        access(all) let seriesId: UInt32
65
66        // Maximum number of editions that can be minted in this Set
67        access(all) let maxEditions: UInt32
68                  
69        // The JSON metadata for each NFT edition can be stored off-chain on IPFS.
70        // This is an optional dictionary of IPFS hashes, which will allow marketplaces
71        // to pull the metadata for each NFT edition
72        access(self) var ipfsMetadataHashes: {UInt32: String}
73
74        // Set level metadata
75        // Dictionary of metadata key value pairs
76        access(self) var metadata: {String: String}
77        
78        init(
79            setId: UInt32,
80            seriesId: UInt32,
81            maxEditions: UInt32,
82            ipfsMetadataHashes: {UInt32: String},
83            metadata: {String: String}) {
84
85            self.setId = setId
86            self.seriesId = seriesId
87            self.maxEditions = maxEditions
88            self.metadata = metadata
89            self.ipfsMetadataHashes = ipfsMetadataHashes
90        }
91
92        access(all) fun getIpfsMetadataHash(editionNum: UInt32): String? {
93            return self.ipfsMetadataHashes[editionNum]
94        }
95
96        access(all) fun getMetadata(): {String: String} {
97            return self.metadata
98        }
99
100        access(all) fun getMetadataField(field: String): String? {
101            return self.metadata[field]
102        }
103    }
104
105    // A SeriesData is a struct that groups metadata for a 
106    // a related group of NFTSets.
107    access(all) struct SeriesData {
108
109        // Unique ID for the Series
110        access(all) let seriesId: UInt32
111
112        // Dictionary of metadata key value pairs
113        access(self) var metadata: {String: String}
114
115        init(
116            seriesId: UInt32,
117            metadata: {String: String}) {
118            self.seriesId = seriesId
119            self.metadata = metadata
120        }
121
122        access(all) fun getMetadata(): {String: String} {
123            return self.metadata
124        }
125    }
126
127
128    // A Series is special resource type that contains functions to mint UFC_NFT NFTs, 
129    // add NFTSets, update NFTSet and Series metadata, and seal Series.
130	access(all) resource Series {
131
132        // Unique ID for the Series
133        access(all) let seriesId: UInt32
134
135        // Array of NFTSets that belong to this Series
136        access(all) var setIds: [UInt32]
137
138        // Series sealed state
139        access(all) var seriesSealedState: Bool;
140
141        // Set sealed state
142        access(self) var setSealedState: {UInt32: Bool};
143
144        // Current number of editions minted per Set
145        access(all) var numberEditionsMintedPerSet: {UInt32: UInt32}
146
147        init(
148            seriesId: UInt32,
149            metadata: {String: String}) {
150
151            self.seriesId = seriesId
152            self.seriesSealedState = false
153            self.numberEditionsMintedPerSet = {}
154            self.setIds = []
155            self.setSealedState = {}
156
157            UFC_NFT.seriesData[seriesId] = SeriesData(
158                    seriesId: seriesId,
159                    metadata: metadata
160            )
161
162            emit SeriesCreated(seriesId: seriesId)   
163        }
164
165        access(all) fun addNftSet(
166            setId: UInt32,
167            maxEditions: UInt32,
168            ipfsMetadataHashes: {UInt32: String},
169            metadata: {String: String}) {
170            pre {
171                self.setIds.contains(setId) == false: "The Set has already been added to the Series."
172            }
173
174            // Create the new Set struct
175            var newNFTSet = NFTSetData(
176                setId: setId,
177                seriesId: self.seriesId,
178                maxEditions: maxEditions,
179                ipfsMetadataHashes: ipfsMetadataHashes,
180                metadata: metadata
181            )
182
183            // Add the NFTSet to the array of Sets
184            self.setIds.append(setId)
185
186            // Initialize the NFT edition count to zero
187            self.numberEditionsMintedPerSet[setId] = 0
188
189            // Store it in the sets mapping field
190            UFC_NFT.setData[setId] = newNFTSet
191
192            emit SetCreated(seriesId: self.seriesId, setId: setId)
193        }
194
195        // updateSeriesMetadata
196        // For practical reasons, a short period of time is given to update metadata
197        // following Series creation or minting of the NFT editions. Once the Series is
198        // sealed, no updates to the Series metadata will be possible - the information
199        // is permanent and immutable.
200        access(all) fun updateSeriesMetadata(metadata: {String: String}) {
201            pre {
202                self.seriesSealedState == false:
203                    "The Series is permanently sealed. No metadata updates can be made."
204            }
205            let newSeriesMetadata = SeriesData(
206                    seriesId: self.seriesId,
207                    metadata: metadata
208            )  
209            // Store updated Series in the Series mapping field
210            UFC_NFT.seriesData[self.seriesId] = newSeriesMetadata
211
212            emit SeriesMetadataUpdated(seriesId: self.seriesId)
213        }
214
215        // updateSetMetadata
216        // For practical reasons, a short period of time is given to update metadata
217        // following Set creation or minting of the NFT editions. Once the Series is
218        // sealed, no updates to the Set metadata will be possible - the information
219        // is permanent and immutable.
220        access(all) fun updateSetMetadata(
221            setId: UInt32,
222            maxEditions: UInt32,
223            ipfsMetadataHashes: {UInt32: String},
224            metadata: {String: String}) {
225            pre {
226                self.seriesSealedState == false:
227                    "The Series is permanently sealed. No metadata updates can be made."
228                self.setIds.contains(setId) == true: "The Set is not part of this Series."
229            }
230            let newSetMetadata = NFTSetData(
231                setId: setId,
232                seriesId: self.seriesId,
233                maxEditions: maxEditions,
234                ipfsMetadataHashes: ipfsMetadataHashes,
235                metadata: metadata
236            )
237            // Store updated Set in the Sets mapping field
238            UFC_NFT.setData[setId] = newSetMetadata
239
240            emit SetMetadataUpdated(seriesId: self.seriesId, setId: setId)
241        }
242
243		// mintUFC_NFT
244        // Mints a new NFT with a new ID
245		// and deposits it in the recipients collection using their collection reference
246        //
247	    access(all) fun mintUFC_NFT(
248            recipient: &{NonFungibleToken.CollectionPublic},
249            tokenId: UInt64,
250            setId: UInt32) {
251            
252            pre {
253                self.numberEditionsMintedPerSet[setId] != nil: "The Set does not exist."
254                self.numberEditionsMintedPerSet[setId]! <= UFC_NFT.getSetMaxEditions(setId: setId)!:
255                    "Set has reached maximum NFT edition capacity."
256            }
257
258            // Gets the number of editions that have been minted so far in 
259            // this set
260            let editionNum: UInt32 = self.numberEditionsMintedPerSet[setId]! + 1
261
262			// deposit it in the recipient's account using their reference
263			recipient.deposit(token: <-create UFC_NFT.NFT(
264                tokenId: tokenId,
265                setId: setId,
266                editionNum: editionNum
267            ))
268
269            // Update the count of Editions minted in the set
270            self.numberEditionsMintedPerSet[setId] = editionNum
271        }
272
273        // mintEditionUFC_NFT
274        // Mints a new NFT with a new ID and specific edition Num (random open edition)
275		// and deposits it in the recipients collection using their collection reference
276        //
277	    access(all) fun mintEditionUFC_NFT(
278            recipient: &{NonFungibleToken.CollectionPublic},
279            tokenId: UInt64,
280            setId: UInt32,
281            edition: UInt32) {
282            
283            pre {
284                self.numberEditionsMintedPerSet[setId] != nil: "The Set does not exist."
285                self.numberEditionsMintedPerSet[setId]! <= UFC_NFT.getSetMaxEditions(setId: setId)!:
286                    "Set has reached maximum NFT edition capacity."
287            }
288
289			// deposit it in the recipient's account using their reference
290			recipient.deposit(token: <-create UFC_NFT.NFT(
291                tokenId: tokenId,
292                setId: setId,
293                editionNum: edition
294            ))
295
296            // Update the count of Editions minted in the set
297            self.numberEditionsMintedPerSet[setId] = self.numberEditionsMintedPerSet[setId]! + 1
298        }
299
300        // batchMintUFC_NFT
301        // Mints multiple new NFTs given and deposits the NFTs
302        // into the recipients collection using their collection reference
303		access(all) fun batchMintUFC_NFT(
304            recipient: &{NonFungibleToken.CollectionPublic},
305            setId: UInt32,
306            tokenIds: [UInt64]) {
307
308            pre {
309                tokenIds.length > 0:
310                    "Number of token Ids must be > 0"
311            }
312
313            for tokenId in tokenIds {
314                self.mintUFC_NFT(
315                    recipient: recipient,
316                    tokenId: tokenId,
317                    setId: setId
318                )
319            }
320		}
321
322        // sealSeries
323        // Once a series is sealed, the metadata for the NFTs in the Series can no
324        // longer be updated
325        //
326        access(all) fun sealSeries() {
327            pre {
328                self.seriesSealedState == false: "The Series is already sealed"
329            }
330            self.seriesSealedState = true
331
332            emit SeriesSealed(seriesId: self.seriesId)
333        }
334	}
335
336    // A resource that represents the UFC_NFT NFT
337    //
338    access(all) resource NFT: NonFungibleToken.NFT, Burner.Burnable {
339        // The token's ID
340        access(all) let id: UInt64
341
342        // The Set id references this NFT belongs to
343        access(all) let setId: UInt32
344
345        // The specific edition number for this NFT
346        access(all) let editionNum: UInt32
347
348        // initializer
349        //
350        init(
351          tokenId: UInt64,
352          setId: UInt32,
353          editionNum: UInt32) {
354
355            self.id = tokenId
356            self.setId = setId
357            self.editionNum = editionNum
358
359            let seriesId = UFC_NFT.getSetSeriesId(setId: setId)!
360
361            emit Minted(id: self.id, setId: setId, seriesId: seriesId)
362        }
363
364        access (contract) fun burnCallback() {
365            emit NFTDestroyed(id: self.id)
366        }
367
368        access(all) fun createEmptyCollection(): @{NonFungibleToken.Collection} {
369            return <- UFC_NFT.createEmptyCollection(nftType: Type<@UFC_NFT.NFT>())
370        }
371
372        access(all) view fun getViews(): [Type] {
373            return [
374                Type<MetadataViews.Display>(),
375                Type<MetadataViews.Royalties>(),
376                Type<MetadataViews.Editions>(),
377                Type<MetadataViews.ExternalURL>(),
378                Type<MetadataViews.NFTCollectionData>(),
379                Type<MetadataViews.NFTCollectionDisplay>(),
380                Type<MetadataViews.Serial>(),
381                Type<MetadataViews.Traits>(),
382                Type<MetadataViews.Medias>()
383            ]
384        }
385        access(all) fun resolveView(_ view: Type): AnyStruct? {
386            switch view {
387                case Type<MetadataViews.Display>():
388                    return MetadataViews.Display(
389                        name: UFC_NFT.getSetMetadataByField(setId: self.setId, field: "name")!,
390                        description: UFC_NFT.getSetMetadataByField(setId: self.setId, field: "description")!,
391                        thumbnail: MetadataViews.HTTPFile(
392                            url: UFC_NFT.getSetMetadataByField(setId: self.setId, field: "preview")!
393                        )
394                    )
395                case Type<MetadataViews.Serial>():
396                    return MetadataViews.Serial(
397                        self.id
398                    )
399                case Type<MetadataViews.Editions>():
400                    let maxEditions = UFC_NFT.setData[self.setId]?.maxEditions ?? 0
401                    let editionName = UFC_NFT.getSetMetadataByField(setId: self.setId, field: "name")!
402                    let editionInfo = MetadataViews.Edition(name: editionName, number: UInt64(self.editionNum), max: maxEditions > 0 ? UInt64(maxEditions) : nil)
403                    let editionList: [MetadataViews.Edition] = [editionInfo]
404                    return MetadataViews.Editions(
405                        editionList
406                    )
407                case Type<MetadataViews.ExternalURL>():
408                    if let externalBaseURL = UFC_NFT.getSetMetadataByField(setId: self.setId, field: "external_token_base_url") {
409                        return MetadataViews.ExternalURL(externalBaseURL.concat("/").concat(self.id.toString()))
410                    }
411                    return MetadataViews.ExternalURL("")
412                case Type<MetadataViews.Royalties>():
413                    let royalties: [MetadataViews.Royalty] = []
414                    // There is only a legacy {String: String} dictionary to store royalty information.
415                    // There may be multiple royalty cuts defined per NFT. Pull each royalty
416                    // based on keys that have the "royalty_addr_" prefix in the dictionary.
417                    for metadataKey in UFC_NFT.getSetMetadata(setId: self.setId)!.keys {
418                        // For efficiency, only check keys that are > 13 chars, which is the length of "royalty_addr_" key
419                        if metadataKey.length >= 13 {
420                            if metadataKey.slice(from: 0, upTo: 13) == "royalty_addr_" {
421                                // A royalty has been found. Use the suffix from the key for the royalty name.
422                                let royaltyName = metadataKey.slice(from: 13, upTo: metadataKey.length)
423                                let royaltyAddress = UFC_NFT.convertStringToAddress(UFC_NFT.getSetMetadataByField(setId: self.setId, field: "royalty_addr_".concat(royaltyName))!)!
424                                let royaltyReceiver: PublicPath = PublicPath(identifier: UFC_NFT.getSetMetadataByField(setId: self.setId, field: "royalty_rcv_".concat(royaltyName))!)!
425                                let royaltyCut = UFC_NFT.getSetMetadataByField(setId: self.setId, field: "royalty_cut_".concat(royaltyName))!
426                                let cutValue: UFix64 = UFC_NFT.royaltyCutStringToUFix64(royaltyCut)
427                                if cutValue != 0.0 {
428                                    royalties.append(MetadataViews.Royalty(
429                                        receiver: getAccount(royaltyAddress).capabilities.get<&{FungibleToken.Receiver}>(royaltyReceiver),
430                                        cut: cutValue,
431                                        description: UFC_NFT.getSetMetadataByField(setId: self.setId, field: "royalty_desc_".concat(royaltyName))!
432                                    )
433                                    )
434                                }
435                            }
436                        }
437                    }
438                    return MetadataViews.Royalties(royalties)
439                case Type<MetadataViews.NFTCollectionData>():
440                    return UFC_NFT.resolveContractView(resourceType: nil, viewType: Type<MetadataViews.NFTCollectionData>())
441                case Type<MetadataViews.NFTCollectionDisplay>():
442                    return UFC_NFT.resolveContractView(resourceType: nil, viewType: Type<MetadataViews.NFTCollectionDisplay>())
443                case Type<MetadataViews.Traits>():
444                    let traitDictionary: {String: AnyStruct} = {}
445                    // There is only a legacy {String: String} dictionary to store trait information.
446                    // There may be multiple traits defined per NFT. Pull trait information
447                    // based on keys that have the "trait_" prefix in the dictionary.
448                    for metadataKey in UFC_NFT.getSetMetadata(setId: self.setId)!.keys {
449                        // For efficiency, only check keys that are > 6 chars, which is the length of "trait_" key
450                        if metadataKey.length >= 6 {
451                            if metadataKey.slice(from: 0, upTo: 6) == "trait_" {
452                                // A trait has been found. Set the trait name to only the trait key suffix.
453                                traitDictionary.insert(key: metadataKey.slice(from: 6, upTo: metadataKey.length), UFC_NFT.getSetMetadataByField(setId: self.setId, field: metadataKey)!)
454                            }
455                        }
456                    }
457                    return MetadataViews.dictToTraits(dict: traitDictionary, excludedNames: [])
458                case Type<MetadataViews.Medias>():
459                    return MetadataViews.Medias(
460                        [
461                            MetadataViews.Media(
462                                file: MetadataViews.HTTPFile(
463                                    url: UFC_NFT.getSetMetadataByField(setId: self.setId, field: "image")!
464                                ),
465                                mediaType: self.getMimeType()
466                            )
467                        ]
468                    )
469            }
470            return nil
471        }
472
473        access(all) fun getMimeType(): String {
474            var metadataFileType = UFC_NFT.getSetMetadataByField(setId: self.setId, field: "image_file_type")!.toLower()
475            switch metadataFileType {
476                case "mp4":
477                    return "video/mp4"
478                case "mov":
479                    return "video/quicktime"
480                case "webm":
481                    return "video/webm"
482                case "ogv":
483                    return "video/ogg"
484                case "png":
485                    return "image/png"
486                case "jpeg":
487                    return "image/jpeg"
488                case "jpg":
489                    return "image/jpeg"
490                case "gif":
491                    return "image/gif"
492                case "webp":
493                    return "image/webp"
494                case "svg":
495                    return "image/svg+xml"
496                case "glb":
497                    return "model/gltf-binary"
498                case "gltf":
499                    return "model/gltf+json"
500                case "obj":
501                    return "model/obj"
502                case "mtl":
503                    return "model/mtl"
504                case "mp3":
505                    return "audio/mpeg"
506                case "ogg":
507                    return "audio/ogg"
508                case "oga":
509                    return "audio/ogg"
510                case "wav":
511                    return "audio/wav"
512                case "html":
513                    return "text/html"
514            }
515            return ""
516        }
517    }
518
519    // Admin is a special authorization resource that 
520    // allows the owner to perform important NFT 
521    // functions
522    //
523    access(all) resource Admin {
524
525        access(all) fun addSeries(seriesId: UInt32, metadata: {String: String}) {
526            pre {
527                UFC_NFT.series[seriesId] == nil:
528                    "Cannot add Series: The Series already exists"
529            }
530
531            // Create the new Series
532            var newSeries <- create Series(
533                seriesId: seriesId,
534                metadata: metadata
535            )
536
537            // Add the new Series resource to the Series dictionary in the contract
538            UFC_NFT.series[seriesId] <-! newSeries
539        }
540
541        access(all) fun borrowSeries(seriesId: UInt32): &Series  {
542            pre {
543                UFC_NFT.series[seriesId] != nil:
544                    "Cannot borrow Series: The Series does not exist"
545            }
546
547            // Get a reference to the Series and return it
548            return (&UFC_NFT.series[seriesId])!
549        }
550
551        access(all) fun createNewAdmin(): @Admin {
552            return <-create Admin()
553        }
554
555    }
556
557    // This is the interface that users can cast their NFT Collection as
558    // to allow others to deposit UFC_NFT into their Collection. It also allows for reading
559    // the details of UFC_NFT in the Collection.
560    access(all) resource interface UFC_NFTCollectionPublic : NonFungibleToken.CollectionPublic {
561        access(all) fun batchDeposit(tokens: @{NonFungibleToken.Collection})
562        access(all) fun borrowUFC_NFT(id: UInt64): &NFT? {
563            // If the result isn't nil, the id of the returned reference
564            // should be the same as the argument to the function
565            post {
566                (result == nil) || (result?.id == id): 
567                    "Cannot borrow UFC_NFT reference: The ID of the returned reference is incorrect"
568            }
569        }
570    }
571
572    // Collection
573    // A collection of UFC_NFT NFTs owned by an account
574    //
575    access(all) resource Collection: UFC_NFTCollectionPublic, NonFungibleToken.Collection {
576        // dictionary of NFT conforming tokens
577        // NFT is a resource type with an UInt64 ID field
578        //
579        access(all) var ownedNFTs: @{UInt64: {NonFungibleToken.NFT}}
580
581        access(all) view fun getSupportedNFTTypes(): {Type: Bool} {
582            let supportedType: {Type: Bool} = {}
583            supportedType[Type<@UFC_NFT.NFT>()] = true
584            return supportedType
585        }
586
587        access(all) view fun isSupportedNFTType(type: Type): Bool {
588            if type == Type<@UFC_NFT.NFT>() {
589                return true
590            }
591            return false
592        }
593
594        // withdraw
595        // Removes an NFT from the collection and moves it to the caller
596        //
597        access(NonFungibleToken.Withdraw) fun withdraw(withdrawID: UInt64): @{NonFungibleToken.NFT} {
598            let token <- self.ownedNFTs.remove(key: withdrawID) ?? panic("missing NFT")
599            emit Withdraw(id: token.id, from: self.owner?.address)
600            return <-token
601        }
602
603        // batchWithdraw withdraws multiple NFTs and returns them as a Collection
604        //
605        // Parameters: ids: An array of IDs to withdraw
606        //
607        // Returns: @NonFungibleToken.Collection: The collection of withdrawn tokens
608        //
609
610        access(NonFungibleToken.Withdraw) fun batchWithdraw(ids: [UInt64]): @{NonFungibleToken.Collection} {
611            // Create a new empty Collection
612            var batchCollection <- create Collection()
613            
614            // Iterate through the ids and withdraw them from the Collection
615            for id in ids {
616                batchCollection.deposit(token: <-self.withdraw(withdrawID: id))
617            }
618            
619            // Return the withdrawn tokens
620            return <-batchCollection
621        }
622
623        // deposit
624        // Takes a NFT and adds it to the collections dictionary
625        // and adds the ID to the id array
626        //
627        access(all) fun deposit(token: @{NonFungibleToken.NFT}) {
628            let token <- token as! @UFC_NFT.NFT
629
630            let id: UInt64 = token.id
631
632            // add the new token to the dictionary which removes the old one
633            let oldToken <- self.ownedNFTs[id] <- token
634            emit Deposit(id: id, to: self.owner?.address)
635            destroy oldToken
636        }
637
638        // batchDeposit takes a Collection object as an argument
639        // and deposits each contained NFT into this Collection
640        access(all) fun batchDeposit(tokens: @{NonFungibleToken.Collection}) {
641
642            // Get an array of the IDs to be deposited
643            let keys = tokens.getIDs()
644
645            // Iterate through the keys in the collection and deposit each one
646            for key in keys {
647                self.deposit(token: <-tokens.withdraw(withdrawID: key))
648            }
649
650            // Destroy the empty Collection
651            destroy tokens
652        }
653
654        // getIDs
655        // Returns an array of the IDs that are in the collection
656        //
657        access(all) view fun getIDs(): [UInt64] {
658            return self.ownedNFTs.keys
659        }
660
661        access(all) view fun getLength(): Int {
662            return self.ownedNFTs.keys.length
663        }
664
665        // borrowNFT
666        // Gets a reference to an NFT in the collection
667        // so that the caller can read its metadata and call its methods
668        //
669        access(all) view fun borrowNFT(_ id: UInt64): &{NonFungibleToken.NFT}? {
670            return &self.ownedNFTs[id]
671        }
672
673        // borrowUFC_NFT
674        // Gets a reference to an NFT in the collection as a UFC_NFT,
675        // exposing all of its fields.
676        // This is safe as there are no functions that can be called on the UFC_NFT.
677        //
678        access(all) fun borrowUFC_NFT(id: UInt64): &NFT? {
679            if let nft = &self.ownedNFTs[id] as &{NonFungibleToken.NFT}? {
680                return nft as! &NFT
681            }
682            return nil
683        }
684
685        // borrowViewResolver
686        // Gets a reference to the MetadataViews resolver in the collection,
687        // giving access to all metadata information made available.
688        //
689        access(all) view fun borrowViewResolver(id: UInt64): &{ViewResolver.Resolver}? {
690            if let nft = &self.ownedNFTs[id] as &{NonFungibleToken.NFT}? {
691                return nft as &{ViewResolver.Resolver}
692            }
693            return nil
694        }
695
696        access(all) fun createEmptyCollection(): @{NonFungibleToken.Collection} {
697            return <- create Collection()
698        }
699
700        // initializer
701        //
702        init () {
703            self.ownedNFTs <- {}
704        }
705    }
706
707    // createEmptyCollection
708    // public function that anyone can call to create a new empty collection
709    //
710    access(all) fun createEmptyCollection(nftType: Type): @{NonFungibleToken.Collection} {
711        return <- create Collection()
712    }
713
714    access(all) view fun getContractViews(resourceType: Type?): [Type] {
715        return [
716            Type<MetadataViews.NFTCollectionData>(),
717            Type<MetadataViews.NFTCollectionDisplay>()
718        ]
719    }
720
721    access(all) fun resolveContractView(resourceType: Type?, viewType: Type): AnyStruct? {
722        switch viewType {
723            case Type<MetadataViews.NFTCollectionData>():
724                return MetadataViews.NFTCollectionData(
725                    storagePath: UFC_NFT.CollectionStoragePath,
726                    publicPath: UFC_NFT.CollectionPublicPath,
727                    publicCollection: Type<&UFC_NFT.Collection>(),
728                    publicLinkedType: Type<&UFC_NFT.Collection>(),
729                    createEmptyCollectionFunction: (fun (): @{NonFungibleToken.Collection} {
730                        return <-UFC_NFT.createEmptyCollection(nftType: Type<@UFC_NFT.NFT>())
731                    })
732                )
733            case Type<MetadataViews.NFTCollectionDisplay>():
734                let squareImage = MetadataViews.Media(
735                    file: MetadataViews.HTTPFile(
736                        url: "https://media-local.gigantik.io/ufc/square.png"
737                    ),
738                    mediaType: "image/png"
739                )
740                let bannerImage = MetadataViews.Media(
741                    file: MetadataViews.HTTPFile(
742                        url: "https://media-local.gigantik.io/ufc/banner.png"
743                    ),
744                    mediaType: "image/png"
745                )
746                var socials: {String: MetadataViews.ExternalURL} = {
747                    "twitter": MetadataViews.ExternalURL("https://twitter.com/UFCStrikeNFT"),
748                    "discord": MetadataViews.ExternalURL("https://discord.gg/UFCStrike"),
749                    "instagram": MetadataViews.ExternalURL("https://instagram.com/ufcstrike")
750                }
751
752                return MetadataViews.NFTCollectionDisplay(
753                    name: "UFC Strike",
754                    description: "Collect the most iconic video highlights from the biggest (and most notorious) fighters from UFC. UFC Strike allows fans to express their fandom like never before with fully licensed UFC video NFTs.",
755                    externalURL: MetadataViews.ExternalURL("https://www.ufcstrike.com/"),
756                    squareImage: squareImage,
757                    bannerImage: bannerImage,
758                    socials: socials
759                )
760        }
761        return nil
762    }
763
764    // getAllSeries returns all the sets
765    //
766    // Returns: An array of all the series that have been created
767    access(all) fun getAllSeries(): [UFC_NFT.SeriesData] {
768        return UFC_NFT.seriesData.values
769    }
770
771    // getAllSets returns all the sets
772    //
773    // Returns: An array of all the sets that have been created
774    access(all) fun getAllSets(): [UFC_NFT.NFTSetData] {
775        return UFC_NFT.setData.values
776    }
777
778    // getSeriesMetadata returns the metadata that the specified Series
779    //            is associated with.
780    // 
781    // Parameters: seriesId: The id of the Series that is being searched
782    //
783    // Returns: The metadata as a String to String mapping optional
784    access(all) fun getSeriesMetadata(seriesId: UInt32): {String: String}? {
785        return UFC_NFT.seriesData[seriesId]?.getMetadata()
786    }
787
788    // getSetMaxEditions returns the the maximum number of NFT editions that can
789    //        be minted in this Set.
790    // 
791    // Parameters: setId: The id of the Set that is being searched
792    //
793    // Returns: The max number of NFT editions in this Set
794    access(all) view fun getSetMaxEditions(setId: UInt32): UInt32? {
795        return UFC_NFT.setData[setId]?.maxEditions
796    }
797
798    // getSetMetadata returns all the metadata associated with a specific Set
799    // 
800    // Parameters: setId: The id of the Set that is being searched
801    //
802    // Returns: The metadata as a String to String mapping optional
803    access(all) fun getSetMetadata(setId: UInt32): {String: String}? {
804        return UFC_NFT.setData[setId]?.getMetadata()
805    }
806
807    // getSetSeriesId returns the Series Id the Set belongs to
808    // 
809    // Parameters: setId: The id of the Set that is being searched
810    //
811    // Returns: The Series Id
812    access(all) fun getSetSeriesId(setId: UInt32): UInt32? {
813        return UFC_NFT.setData[setId]?.seriesId
814    }
815
816    // getSetMetadata returns all the ipfs hashes for each nft 
817    //     edition in the Set.
818    // 
819    // Parameters: setId: The id of the Set that is being searched
820    //
821    // Returns: The ipfs hashes of nft editions as a Array of Strings
822    access(all) fun getIpfsMetadataHashByNftEdition(setId: UInt32, editionNum: UInt32): String? {
823        // Don't force a revert if the setId or field is invalid
824        if let set = UFC_NFT.setData[setId] {
825            return set.getIpfsMetadataHash(editionNum: editionNum)
826        } else {
827            return nil
828        }
829    }
830
831    // getSetMetadataByField returns the metadata associated with a 
832    //                        specific field of the metadata
833    // 
834    // Parameters: setId: The id of the Set that is being searched
835    //             field: The field to search for
836    //
837    // Returns: The metadata field as a String Optional
838    access(all) fun getSetMetadataByField(setId: UInt32, field: String): String? {
839        // Don't force a revert if the setId or field is invalid
840        if let set = UFC_NFT.setData[setId] {
841            return set.getMetadataField(field: field)
842        } else {
843            return nil
844        }
845    }
846
847    // stringToAddress Converts a string to a Flow address
848    // 
849    // Parameters: input: The address as a String
850    //
851    // Returns: The flow address as an Address Optional
852	access(all) fun convertStringToAddress(_ input: String): Address? {
853		var address=input
854		if input.utf8[1] == 120 {
855			address = input.slice(from: 2, upTo: input.length)
856		}
857		var r:UInt64 = 0 
858		var bytes = address.decodeHex()
859
860		while bytes.length>0{
861			r = r  + (UInt64(bytes.removeFirst()) << UInt64(bytes.length * 8 ))
862		}
863
864		return Address(r)
865	}
866
867    // royaltyCutStringToUFix64 Converts a royalty cut string
868    //        to a UFix64
869    // 
870    // Parameters: royaltyCut: The cut value 0.0 - 1.0 as a String
871    //
872    // Returns: The royalty cut as a UFix64
873    access(all) fun royaltyCutStringToUFix64(_ royaltyCut: String): UFix64 {
874        var decimalPos = 0
875        if royaltyCut[0] == "." {
876            decimalPos = 1
877        } else if royaltyCut[1] == "." {
878            if royaltyCut[0] == "1" {
879                // "1" in the first postiion must be 1.0 i.e. 100% cut
880                return 1.0
881            } else if royaltyCut[0] == "0" {
882                decimalPos = 2
883            }
884        } else {
885            // Invalid royalty value
886            return 0.0
887        }
888
889        var royaltyCutStrLen = royaltyCut.length
890        if royaltyCut.length > (8 + decimalPos) {
891            // UFix64 is capped at 8 digits after the decimal
892            // so truncate excess decimal values from the string
893            royaltyCutStrLen = (8 + decimalPos)
894        }
895        let royaltyCutPercentValue = royaltyCut.slice(from: decimalPos, upTo: royaltyCutStrLen)
896        var bytes = royaltyCutPercentValue.utf8
897        var i = 0
898        var cutValueInteger: UInt64 = 0
899        var cutValueDivisor: UFix64 = 1.0
900        let zeroAsciiIntValue: UInt64 = 48
901        // First convert the string to a non-decimal Integer
902        while i < bytes.length {
903            cutValueInteger = (cutValueInteger * 10) + UInt64(bytes[i]) - zeroAsciiIntValue
904            cutValueDivisor = cutValueDivisor * 10.0
905            i = i + 1
906        }
907
908        // Convert the resulting Integer to a decimal in the range 0.0 - 0.99999999
909        return (UFix64(cutValueInteger) / cutValueDivisor)
910    }
911
912    // initializer
913    //
914	init() {
915        // Set named paths
916        self.CollectionStoragePath = /storage/UFC_NFTCollection
917        self.CollectionPublicPath = /public/UFC_NFTCollection
918        self.AdminStoragePath = /storage/UFC_NFTAdmin
919
920        self.setData = {}
921        self.seriesData = {}
922        self.series <- {}
923
924        // Put Admin in storage
925        self.account.storage.save(<-create Admin(), to: self.AdminStoragePath)
926
927        let collectionCap: Capability<&UFC_NFT.Collection> = self.account.capabilities.storage.issue<&UFC_NFT.Collection>(self.CollectionStoragePath)
928        self.account.capabilities.publish(collectionCap, at: self.CollectionPublicPath)
929	}
930}
931