Smart Contract

FantastecNFT

A.4bbff461fa8f6192.FantastecNFT

Deployed

3d ago
Feb 24, 2026, 11:29:58 PM UTC

Dependents

25 imports
1import FungibleToken from 0xf233dcee88fe0abe
2import NonFungibleToken from 0x1d7e57aa55817448
3import MetadataViews from 0x1d7e57aa55817448
4import FantastecSwapDataV2 from 0x4bbff461fa8f6192
5import FantastecSwapDataProperties from 0x4bbff461fa8f6192
6import ViewResolver from 0x1d7e57aa55817448
7
8access(all) contract FantastecNFT: NonFungibleToken {
9
10  access(all) entitlement Owner
11
12  // Events
13  //
14  access(all) event ContractInitialized()
15  access(all) event Withdraw(id: UInt64, from: Address?)
16  access(all) event Deposit(id: UInt64, to: Address?)
17  access(all) event Minted(id: UInt64)
18  access(all) event Destroyed(id: UInt64, reason: String)
19
20  // Named Paths
21  //
22  access(all) let CollectionStoragePath: StoragePath
23  access(all) let CollectionPublicPath: PublicPath
24  access(all) let MinterStoragePath: StoragePath
25
26  // totalSupply
27  // The total number of FantastecNFT that have ever been minted
28  access(all) var totalSupply: UInt64
29
30  access(all) struct Item {
31    access(all) let id: UInt64
32    access(all) let cardId: UInt64
33    access(all) let edition: UInt64
34    access(all) let mintNumber: UInt64
35    access(all) let licence: String
36    access(all) let dateMinted: String
37    access(all) let metadata: {String: String}
38    init(
39        id: UInt64,
40        cardId: UInt64,
41        edition: UInt64,
42        mintNumber: UInt64,
43        licence: String,
44        dateMinted: String,
45        metadata: {String: String}){
46      self.id = id
47      self.cardId = cardId
48      self.edition = edition
49      self.mintNumber = mintNumber
50      self.licence = licence
51      self.dateMinted = dateMinted
52      self.metadata = metadata
53    }
54  }
55
56  // NFT: FantastecNFT.NFT
57  // Raw NFT, doesn't currently restrict the caller instantiating an NFT
58  //
59  access(all) resource NFT: NonFungibleToken.NFT {
60    // The token's ID
61    access(all) let id: UInt64
62    access(all) let cardId: UInt64
63    access(all) let edition: UInt64
64    access(all) let mintNumber: UInt64
65    access(all) let licence: String
66    access(all) let dateMinted: String
67    access(all) let metadata: {String: String}
68
69    // initializer
70    //
71    init(item: Item) {
72      self.id = item.id
73      self.cardId = item.cardId
74      self.edition = item.edition
75      self.mintNumber = item.mintNumber
76      self.licence = item.licence
77      self.dateMinted = item.dateMinted
78      self.metadata = item.metadata
79    }
80
81    access(self) fun concatenateStrings(_ strings: [String?]): String {
82      var res = ""
83      for string in strings {
84        if (string != nil) {
85          if (res.length > 0) {
86            res = res.concat(", ")
87          }
88          res = res.concat(string!)
89        }
90      }
91      return res
92    }
93
94    access(self) fun getCard(): FantastecSwapDataV2.CardData? {
95      let card = FantastecSwapDataV2.getCardById(id: self.cardId)
96      return card
97    }
98
99    access(self) fun getCardCollection(): &FantastecSwapDataV2.CardCollectionData? {
100      let card = self.getCard()
101      if (card != nil) {
102        let cardCollection = FantastecSwapDataV2.getCardCollectionById(id: card!.collectionId)
103        return cardCollection
104      }
105      return nil
106    }
107
108    access(self) fun getCardRoyalties(): [MetadataViews.Royalty] {
109      let card = self.getCard()
110      let cardMetadata = card?.metadata ?? {}
111      let royaltiesMetadata = cardMetadata["royalties"]
112      var royalties: [MetadataViews.Royalty] = []
113      if (royaltiesMetadata != nil) {
114        for royaltyElement in royaltiesMetadata! {
115          let royalty = royaltyElement as! FantastecSwapDataProperties.Royalty
116          let receiver = getAccount(royalty.address).capabilities.get<&{FungibleToken.Receiver}>(/public/flowTokenReceiver)
117          let cut = royalty.percentage / 100.0
118          let description = royalty.id.toString()
119          royalties.append(
120            MetadataViews.Royalty(receiver: receiver, cut: cut, description: description)
121          )
122        }
123      }
124      return royalties
125    }
126
127    access(self) fun getCardMintVolume(): FantastecSwapDataProperties.MintVolume? {
128      let card = self.getCard()
129      let cardMetadata = card?.metadata ?? {}
130      let mintVolumeMetadata = cardMetadata["mintVolume"]
131      if (mintVolumeMetadata != nil && mintVolumeMetadata!.length > 0) {
132        let mintVolume = mintVolumeMetadata![0] as? FantastecSwapDataProperties.MintVolume
133        return mintVolume
134      }
135      return nil
136    }
137
138    access(self) fun getCardMediaFile(_ mediaType: String): MetadataViews.HTTPFile {
139      let card = self.getCard()
140      let cardMetadata = card?.metadata ?? {}
141      let mediaMetadata = cardMetadata["media"]
142      if (mediaMetadata != nil) {
143        for mediaElement in mediaMetadata! {
144          let media = mediaElement as! FantastecSwapDataProperties.Media
145          if (media.mediaType == mediaType) {
146            return MetadataViews.HTTPFile(url: media.url)
147          }
148        }
149      }
150      return MetadataViews.HTTPFile(url: "")
151    }
152
153    access(self) fun getCardCollectionMediaFile(_ mediaType: String): MetadataViews.HTTPFile {
154      let cardCollection = self.getCardCollection()
155      let cardCollectionMetadata = cardCollection?.metadata ?? &{}
156      let mediaMetadata = cardCollectionMetadata["media"]
157      if (mediaMetadata != nil) {
158        for mediaElement in mediaMetadata! {
159          let media = mediaElement as! FantastecSwapDataProperties.Media
160          if (media.mediaType == mediaType) {
161            return MetadataViews.HTTPFile(url: media.url)
162          }
163        }
164      }
165      return MetadataViews.HTTPFile(url: "")
166    }
167
168    access(self) fun getCardCollectionSocials(): {String: MetadataViews.ExternalURL} {
169      let cardCollection = self.getCardCollection()
170      let cardCollectionMetadata = cardCollection?.metadata ?? &{}
171      let socialsMetadata = cardCollectionMetadata["socials"]
172      var socialsDictionary: {String: MetadataViews.ExternalURL} = {}
173      if (socialsMetadata != nil) {
174        for socialElement in socialsMetadata! {
175          let social = socialElement as! FantastecSwapDataProperties.Social
176          socialsDictionary[social.type] = MetadataViews.ExternalURL(social.url)
177        }
178      }
179      return socialsDictionary
180    }
181
182    access(self) fun getCardCollectionPartner(): FantastecSwapDataProperties.Partner? {
183      let cardCollection = self.getCardCollection()
184      let cardCollectionMetadata = cardCollection?.metadata ?? &{}
185      let partnerMetadata = cardCollectionMetadata["partner"]
186      if (partnerMetadata != nil && partnerMetadata!.length > 0) {
187        let partner = partnerMetadata![0] as? FantastecSwapDataProperties.Partner
188        return partner
189      }
190      return nil
191    }
192
193    access(self) fun getCardCollectionTeam(): FantastecSwapDataProperties.Team? {
194      let cardCollection = self.getCardCollection()
195      let cardCollectionMetadata = cardCollection?.metadata ?? &{}
196      let teamMetadata = cardCollectionMetadata["team"]
197      if (teamMetadata != nil && teamMetadata!.length > 0) {
198        let team = teamMetadata![0] as? FantastecSwapDataProperties.Team
199        return team
200      }
201      return nil
202    }
203
204    access(self) fun getCardCollectionSeason(): FantastecSwapDataProperties.Season? {
205      let cardCollection = self.getCardCollection()
206      let cardCollectionMetadata = cardCollection?.metadata ?? &{}
207      let seasonMetadata = cardCollectionMetadata["season"]
208      if (seasonMetadata != nil && seasonMetadata!.length > 0) {
209        let season = seasonMetadata![0] as? FantastecSwapDataProperties.Season
210        return season
211      }
212      return nil
213    }
214
215    access(self) fun getCardCollectionPlayer(): FantastecSwapDataProperties.Player? {
216      let card = self.getCard()
217      let cardMetadata = card?.metadata ?? {}
218      let playerMetadata = cardMetadata["player"]
219      if (playerMetadata != nil && playerMetadata!.length > 0) {
220        let player = playerMetadata![0] as? FantastecSwapDataProperties.Player
221        return player
222      }
223      return nil
224    }
225
226    access(self) fun getCardCollectionRedeemInfo(): FantastecSwapDataProperties.RedeemInfoV2? {
227      let card = self.getCard()
228      let cardMetadata = card?.metadata ?? {}
229      let redeemInfoMetadata = cardMetadata["redeemInfo"]
230      if (redeemInfoMetadata != nil && redeemInfoMetadata!.length > 0) {
231        let redeemInfo = redeemInfoMetadata![0] as? FantastecSwapDataProperties.RedeemInfoV2
232        return redeemInfo
233      }
234      return nil
235    }
236
237    access(self) fun getNFTCollectionDisplayDescription(): String {
238      let cardCollection = self.getCardCollection()
239      var description = cardCollection?.description
240      if (description == nil) {
241        let season = self.getCardCollectionSeason()
242        let partner = self.getCardCollectionPartner()
243        let team = self.getCardCollectionTeam()
244        let level = self.getNFTLevel()
245        description = self.concatenateStrings([season?.name, partner?.name, team?.name, level?.name])
246      }
247      return description!
248    }
249
250    access(self) fun extractLevelFromMetadata(
251      metadata: &{String: [{FantastecSwapDataProperties.MetadataElement}]}
252    ): FantastecSwapDataProperties.Level? {
253      let levelMetadata = metadata["level"]
254      if (levelMetadata != nil && levelMetadata!.length > 0) {
255        let level = levelMetadata![0] as? FantastecSwapDataProperties.Level
256        return level
257      }
258      return nil
259    }
260
261    access(self) fun getNFTLevel(): FantastecSwapDataProperties.Level? {
262      // If the card has a level, use that - otherwise use the collection level
263      let card = self.getCard()
264      let cardMetadata = card?.metadata ?? {}
265      let ref: &{String: [{FantastecSwapDataProperties.MetadataElement}]} = &cardMetadata
266      var level = self.extractLevelFromMetadata(metadata: ref)
267
268      if (level == nil) {
269        let cardCollection = self.getCardCollection()
270        let cardCollectionMetadata = cardCollection?.metadata ?? &{}
271        level = self.extractLevelFromMetadata(metadata: cardCollectionMetadata)
272      }
273      return level
274    }
275
276    access(self) fun getNFTMintVolume(): UInt64? {
277      // If the card has a mint volume, use that - otherwise use the collection mint volume
278      let cardMintVolume = self.getCardMintVolume()
279      // Card mint volume is stored in metadata
280      if (cardMintVolume != nil) {
281        return cardMintVolume!.value
282      }
283      let cardCollection = self.getCardCollection()
284      if (cardCollection != nil) {
285        return cardCollection!.mintVolume
286      }
287      return nil
288    }
289
290    access(self) fun getTraits(): MetadataViews.Traits {
291      let traits = MetadataViews.dictToTraits(dict: self.metadata, excludedNames: [])
292
293      let dateMintedTrait = MetadataViews.Trait(name: "DateMinted", value: self.dateMinted, displayType: nil, rarity: nil)
294      traits.addTrait(dateMintedTrait)
295
296      let partner = self.getCardCollectionPartner()
297      if (partner != nil) {
298        let partnerTrait = MetadataViews.Trait(name: "Partner", value: partner!.name, displayType: nil, rarity: nil)
299        traits.addTrait(partnerTrait)
300      }
301      let season = self.getCardCollectionSeason()
302      if (season != nil) {
303        let year = season!.startDate.concat("-").concat(season!.endDate)
304        let yearTrait = MetadataViews.Trait(name: "Year", value: year, displayType: nil, rarity: nil)
305        traits.addTrait(yearTrait)
306      }
307      let team = self.getCardCollectionTeam()
308      if (team != nil) {
309        let teamTrait = MetadataViews.Trait(name: "TeamName", value: team!.name, displayType: nil, rarity: nil)
310        traits.addTrait(teamTrait)
311
312        let teamGenderTrait = MetadataViews.Trait(name: "TeamGender", value: team!.gender, displayType: nil, rarity: nil)
313        traits.addTrait(teamGenderTrait)
314      }
315      let player = self.getCardCollectionPlayer()
316      if (player != nil) {
317        let playerNameTrait = MetadataViews.Trait(name: "PlayerName", value: player!.name, displayType: nil, rarity: nil)
318        traits.addTrait(playerNameTrait)
319
320        let playerGenderTrait = MetadataViews.Trait(name: "PlayerGender", value: player!.gender, displayType: nil, rarity: nil)
321        traits.addTrait(playerGenderTrait)
322
323        if (player!.shirtNumber != nil) {
324          let shirtNumberTrait = MetadataViews.Trait(name: "PlayerShirtNumber", value: player!.shirtNumber, displayType: nil, rarity: nil)
325          traits.addTrait(shirtNumberTrait)
326        }
327
328        if (player!.position != nil) {
329          let positionTrait = MetadataViews.Trait(name: "PlayerPosition", value: player!.position, displayType: nil, rarity: nil)
330          traits.addTrait(positionTrait)
331        }
332      }
333      let redeemInfo = self.getCardCollectionRedeemInfo()
334      if (redeemInfo != nil) {
335        let retailerIdTrait = MetadataViews.Trait(name: "RetailerId", value: redeemInfo!.id, displayType: nil, rarity: nil)
336        traits.addTrait(retailerIdTrait)
337
338        let retailerNameTrait = MetadataViews.Trait(name: "RetailerName", value: redeemInfo!.retailerName, displayType: nil, rarity: nil)
339        traits.addTrait(retailerNameTrait)
340
341        let retailerPinHashTrait = MetadataViews.Trait(name: "RetailerPinHash", value: redeemInfo!.retailerPinHash, displayType: nil, rarity: nil)
342        traits.addTrait(retailerPinHashTrait)
343
344        let retailerAddressTrait = MetadataViews.Trait(name: "RetailerAddress", value: redeemInfo!.retailerAddress, displayType: nil, rarity: nil)
345        traits.addTrait(retailerAddressTrait)
346
347        if redeemInfo!.validFrom != nil {
348          let validFromTrait = MetadataViews.Trait(name: "ValidFrom", value: redeemInfo!.validFrom, displayType: nil, rarity: nil)
349          traits.addTrait(validFromTrait)
350        }
351
352        if redeemInfo!.validTo != nil {
353          let validFromTrait = MetadataViews.Trait(name: "ValidTo", value: redeemInfo!.validFrom, displayType: nil, rarity: nil)
354          traits.addTrait(validFromTrait)
355        }
356
357        if redeemInfo!.type != nil {
358          let redeemTypeTrait = MetadataViews.Trait(name: "RedeemType", value: redeemInfo!.type, displayType: nil, rarity: nil)
359          traits.addTrait(redeemTypeTrait)
360        }
361
362        if redeemInfo!.t_and_cs != nil {
363          let tAndCsTrait = MetadataViews.Trait(name: "TAndCs", value: redeemInfo!.t_and_cs, displayType: nil, rarity: nil)
364          traits.addTrait(tAndCsTrait)
365        }
366
367        if redeemInfo!.description != nil {
368          let descriptionTrait = MetadataViews.Trait(name: "Description", value: redeemInfo!.description, displayType: nil, rarity: nil)
369          traits.addTrait(descriptionTrait)
370        }
371      }
372      let card = self.getCard()
373      if (card != nil) {
374        let cardIdTrait = MetadataViews.Trait(name: "CardId", value: card!.id, displayType: nil, rarity: nil)
375        traits.addTrait(cardIdTrait)
376
377        let cardTypeTrait = MetadataViews.Trait(name: "CardType", value: card!.type, displayType: nil, rarity: nil)
378        traits.addTrait(cardTypeTrait)
379
380        let cardAspectRatioTrait = MetadataViews.Trait(name: "CardAspectRatio", value: card!.aspectRatio, displayType: nil, rarity: nil)
381        traits.addTrait(cardAspectRatioTrait)
382
383        let collectionIdTrait = MetadataViews.Trait(name: "CollectionId", value: card!.collectionId, displayType: nil, rarity: nil)
384        traits.addTrait(collectionIdTrait)
385      }
386      let mintVolume = self.getNFTMintVolume()
387      if (mintVolume != nil) {
388        let mintVolumeTrait = MetadataViews.Trait(name: "MintVolume", value: mintVolume!, displayType: nil, rarity: nil)
389        traits.addTrait(mintVolumeTrait)
390      }
391
392      return traits
393    }
394
395    access(all) view fun getViews(): [Type] {
396      return [
397        Type<MetadataViews.Display>(),
398        Type<MetadataViews.Editions>(),
399        Type<MetadataViews.ExternalURL>(),
400        Type<MetadataViews.NFTCollectionData>(),
401        Type<MetadataViews.NFTCollectionDisplay>(),
402        Type<MetadataViews.Serial>(),
403        Type<MetadataViews.Traits>(),
404        Type<MetadataViews.Royalties>()
405      ]
406    }
407
408    access(all) fun resolveView(_ view: Type): AnyStruct? {
409      switch (view) {
410        case Type<MetadataViews.Display>():
411          let card = self.getCard()
412          if (card == nil) {
413            return nil
414          }
415          let name = card!.name
416          let cardCollection = self.getCardCollection()
417          var description = cardCollection != nil ? name.concat(", ").concat(cardCollection!.title) : name
418          let level = self.getNFTLevel()
419          if (level != nil) {
420            description = description.concat(", ").concat(level!.name)
421          }
422          var thumbnail = self.getCardMediaFile("CARD_THUMBNAIL")
423
424          let display = MetadataViews.Display(
425            name: name,
426            description: description,
427            thumbnail: thumbnail
428          )
429          return display
430
431        case Type<MetadataViews.Medias>():
432          let items: [MetadataViews.Media] = []
433          let animation = self.getCardMediaFile("CARD_ANIMATION")
434          if (animation.uri() != "") {
435            let animationMedia = MetadataViews.Media(
436              file: animation,
437              mediaType: "video/mp4"
438            )
439            items.append(animationMedia)
440          }
441          let frame = self.getCardMediaFile("CARD_FRAME")
442          if (frame.uri() != "") {
443            let frameMedia = MetadataViews.Media(
444              file: frame,
445              mediaType: "video/mp4"
446            )
447            items.append(frameMedia)
448          }
449          let image = self.getCardMediaFile("CARD_IMAGE")
450          if (image.uri() != "") {
451            let imageMedia = MetadataViews.Media(
452              file: image,
453              mediaType: "image/png" // TODO: get file extensiuon
454            )
455            items.append(imageMedia)
456          }
457          let thumbnail = self.getCardMediaFile("CARD_THUMBNAIL")
458          if (thumbnail.uri() != "") {
459            let thumbnailMedia = MetadataViews.Media(
460              file: thumbnail,
461              mediaType: "image/jpeg"
462            )
463            items.append(thumbnailMedia)
464          }
465          let medias = MetadataViews.Medias(items)
466          return medias
467
468        case Type<MetadataViews.Editions>():
469          let card = self.getCard()
470          if (card == nil) {
471            return nil
472          }
473          let name = card!.name
474          let number = self.mintNumber
475          let cardCollection = self.getCardCollection()
476          var max: UInt64? = self.getNFTMintVolume() ?? 0
477          if max! < number {
478            max = nil
479          }
480          let editionInfo = MetadataViews.Edition(name: name, number: number, max: max)
481          return MetadataViews.Editions([editionInfo])
482
483        case Type<MetadataViews.ExternalURL>():
484          return MetadataViews.ExternalURL("https://www.fantastec-swap.io/nft/view?id=".concat(self.id.toString()))
485
486        case Type<MetadataViews.NFTCollectionData>():
487          return MetadataViews.NFTCollectionData(
488            storagePath: FantastecNFT.CollectionStoragePath,
489            publicPath: FantastecNFT.CollectionPublicPath,
490            publicCollection: Type<&{FantastecNFT.FantastecNFTCollectionPublic}>(),
491            publicLinkedType: Type<&{FantastecNFT.FantastecNFTCollectionPublic,NonFungibleToken.Collection}>(),
492            createEmptyCollectionFunction: (fun (): @{NonFungibleToken.Collection} {
493                return <- FantastecNFT.createEmptyCollection(nftType: Type<@NFT>())
494            })
495          )
496
497        case Type<MetadataViews.NFTCollectionDisplay>():
498          let cardCollection = self.getCardCollection()
499          let name = cardCollection?.title ?? ""
500          let description = self.getNFTCollectionDisplayDescription()
501          let squareImageMedia = MetadataViews.Media(
502            file: self.getCardCollectionMediaFile("COLLECTION_LOGO_IMAGE"),
503            mediaType: "image/png"
504          )
505          let bannerImageMedia = MetadataViews.Media(
506            file: self.getCardCollectionMediaFile("COLLECTION_HEADER_IMAGE"),
507            mediaType: "image/png"
508          )
509          return MetadataViews.NFTCollectionDisplay(
510            name: name,
511            description: description,
512            externalURL: MetadataViews.ExternalURL(""),
513            squareImage: squareImageMedia,
514            bannerImage: bannerImageMedia,
515            socials: self.getCardCollectionSocials()
516          )
517
518        case Type<MetadataViews.Serial>():
519          return MetadataViews.Serial(self.uuid)
520
521        case Type<MetadataViews.Traits>():
522          return self.getTraits()
523
524        case Type<MetadataViews.Royalties>():
525          return MetadataViews.Royalties(self.getCardRoyalties())
526      }
527
528      return nil
529    }
530
531    access(all) fun createEmptyCollection(): @{NonFungibleToken.Collection} {
532        return <- FantastecNFT.createEmptyCollection(nftType: self.getType())
533    }
534  }
535
536  // This is the interface that users can cast their FantastecNFT Collection as
537  // to allow others to deposit FantastecNFTs into their Collection. It also allows for reading
538  // the details of FantastecNFTs in the Collection.
539  access(all) resource interface FantastecNFTCollectionPublic: NonFungibleToken.Collection {
540    access(all) fun deposit(token: @{NonFungibleToken.NFT})
541    access(all) fun borrowFantastecNFT(id: UInt64): &FantastecNFT.NFT? {
542      post {
543        (result == nil) || (result?.id == id):
544          "Cannot borrow FantastecNFT reference: The ID of the returned reference is incorrect"
545      }
546    }
547  }
548
549  // Collection
550  // A collection of Moment NFTs owned by an account
551  //
552  access(all) resource Collection: FantastecNFTCollectionPublic {
553    // dictionary of NFT conforming tokens
554    // NFT is a resource type with an UInt64 ID field
555    // metadataObjs is a dictionary of metadata mapped to NFT IDs
556    //
557    access(all) var ownedNFTs: @{UInt64: {NonFungibleToken.NFT}}
558
559    // deposit
560    // Takes a NFT and adds it to the collections dictionary
561    // and adds the ID to the id array
562    //
563    access(all) fun deposit(token: @{NonFungibleToken.NFT}) {
564      let token <- token
565
566      let id: UInt64 = token.id
567
568      // add the new token to the dictionary which removes the old one
569      let oldToken <- self.ownedNFTs[id] <- token
570
571      emit Deposit(id: id, to: self.owner?.address)
572
573      if (oldToken != nil){
574        emit Destroyed(id: id, reason: "replaced existing resource with the same id")
575      }
576
577      destroy oldToken
578    }
579
580    // getIDs
581    // Returns an array of the IDs that are in the collection
582    //
583    access(all) view fun getIDs(): [UInt64] {
584      return self.ownedNFTs.keys
585    }
586
587    // borrowNFT
588    // Gets a reference to an NFT in the collection
589    // so that the caller can read its metadata and call its methods
590    //
591    access(all) view fun borrowNFT(_ id: UInt64): &{NonFungibleToken.NFT}? {
592      return &self.ownedNFTs[id]
593    }
594
595    access(all) view fun getSupportedNFTTypes(): {Type: Bool} {
596        return {Type<@NFT>(): true}
597    }
598
599    access(all) view fun isSupportedNFTType(type: Type): Bool {
600        return type == Type<@NFT>()
601    }
602
603    access(all) fun createEmptyCollection(): @{NonFungibleToken.Collection} {
604        return <- create Collection()
605    }
606
607    // borrowFantastecNFT
608    // Gets a reference to an NFT in the collection as a FantastecNFT,
609    // exposing all of its fields.
610    // This is safe as there are no functions that can be called on the FantastecNFT.
611    //
612    access(all) fun borrowFantastecNFT(id: UInt64): &FantastecNFT.NFT? {
613      if self.ownedNFTs[id] != nil {
614        let ref = (&self.ownedNFTs[id] as &{NonFungibleToken.NFT}?)!
615        return ref as! &FantastecNFT.NFT
616      }
617
618      return nil
619    }
620
621    // withdraw
622    // Removes an NFT from the collection and moves it to the caller
623    //
624    access(NonFungibleToken.Withdraw) fun withdraw(withdrawID: UInt64): @{NonFungibleToken.NFT} {
625      let token <- self.ownedNFTs.remove(key: withdrawID) ?? panic("missing NFT")
626
627      emit Withdraw(id: token.id, from: self.owner?.address)
628
629      return <-token
630    }
631
632    // initializer
633    //
634    init () {
635      self.ownedNFTs <- {}
636    }
637  }
638
639  // NFTMinter
640  // Resource that an admin or something similar would own to be
641  // able to mint new NFTs
642  //
643  access(all) resource NFTMinter {
644    // Mints a new NFTs
645    // Increments mintNumber
646    // returns the newly minted NFT
647    //
648    access(Owner) fun mintAndReturnNFT(
649        cardId: UInt64, 
650        edition: UInt64, 
651        mintNumber: UInt64, 
652        licence: String, 
653        dateMinted: String, 
654        metadata: {String: String}): @FantastecNFT.NFT {
655
656      let newId = FantastecNFT.totalSupply + 1
657
658      let nftData: Item = Item(
659        id: FantastecNFT.totalSupply,
660        cardId: cardId,
661        edition: edition,
662        mintNumber: mintNumber,
663        licence: licence,
664        dateMinted: dateMinted,
665        metadata: metadata,
666      )
667      var newNFT <-create FantastecNFT.NFT(item: nftData)
668
669      // emit and update contract
670      emit Minted(id: nftData.id)
671
672      // update contracts
673      FantastecNFT.totalSupply = newId
674
675      return <- newNFT
676    }
677
678    // Mints a new NFTs
679    // Increments mintNumber
680    // deposits the NFT into the recipients collection using their collection reference
681    //
682    access(Owner) fun mintNFT(
683        recipient: &{NonFungibleToken.CollectionPublic}, 
684        cardId: UInt64, 
685        edition: UInt64, 
686        mintNumber: UInt64, 
687        licence: String, 
688        dateMinted: String, 
689        metadata: {String: String}) {
690
691      var newNFT <- self.mintAndReturnNFT(
692        cardId: cardId,
693        edition: edition,
694        mintNumber: mintNumber,
695        licence: licence,
696        dateMinted: dateMinted,
697        metadata: metadata
698      )
699
700      // deposit it in the recipient's account using their reference
701      recipient.deposit(token: <- newNFT)
702    }
703  }
704
705    /// Function that resolves a metadata view for this contract.
706    ///
707    /// @param view: The Type of the desired view.
708    /// @return A structure representing the requested view.
709    ///
710    access(all) fun resolveContractView(resourceType: Type?, viewType: Type): AnyStruct? {
711        switch viewType {
712            case Type<MetadataViews.NFTCollectionData>():
713                return MetadataViews.NFTCollectionData(
714                    storagePath: FantastecNFT.CollectionStoragePath,
715                    publicPath: FantastecNFT.CollectionPublicPath,
716                    publicCollection: Type<&{FantastecNFT.FantastecNFTCollectionPublic}>(),
717                    publicLinkedType: Type<&{FantastecNFT.FantastecNFTCollectionPublic}>(),
718                    createEmptyCollectionFunction: (fun (): @{NonFungibleToken.Collection} {
719                        return <-FantastecNFT.createEmptyCollection(nftType: Type<@NFT>())
720                    })
721                )
722            case Type<MetadataViews.NFTCollectionDisplay>():
723                return MetadataViews.NFTCollectionDisplay(
724                        name: "Fantastec SWAP",
725                        description: "Collect and Swap NFTs created exclusively for European Football clubs Real Madrid Mens and Womens, Arsenal Mens and Womens, Borussia Dortmund, and US College Athletes at Michigan State University, University of Michigan, University of Illinois, and Syracuse University.",
726                        externalURL: MetadataViews.ExternalURL("https://fantastec-swap.io"),
727                        squareImage: MetadataViews.Media(
728                            file: MetadataViews.HTTPFile(
729                                url: "https://bafkreihvx3vfgnpn4ygfdcq4w7pdlamw4maasok7xuzcfoutm3lbitwprm.ipfs.nftstorage.link/"
730                            ),
731                            mediaType: "image/jpeg"
732                        ),
733                        bannerImage: MetadataViews.Media(
734                            file: MetadataViews.HTTPFile(
735                                url: "https://bafybeicadjtenkcpdts3rf43a7dgcjjfasihcaed46yxkdgvehj4m33ate.ipfs.nftstorage.link/"
736                            ),
737                            mediaType: "image/jpeg"
738                        ),
739                        socials: {
740                            "twitter": MetadataViews.ExternalURL("https://twitter.com/fantastecSWAP")
741                        }
742                    )
743        }
744        return nil
745    }
746
747    /// Function that returns all the Metadata Views implemented by a Non Fungible Token
748    ///
749    /// @return An array of Types defining the implemented views. This value will be used by
750    ///         developers to know which parameter to pass to the resolveView() method.
751    ///
752    access(all) view fun getContractViews(resourceType: Type?): [Type] {
753        return [
754            Type<MetadataViews.NFTCollectionData>(),
755            Type<MetadataViews.NFTCollectionDisplay>()
756        ]
757    }
758
759    access(all) fun getTotalSupply(): UInt64 {
760        return FantastecNFT.totalSupply;
761    }
762
763    access(all) fun createEmptyCollection(nftType: Type): @{NonFungibleToken.Collection} {
764        return <- create Collection()
765    }
766
767  init(){
768    // Set our named paths
769    self.CollectionStoragePath = /storage/FantastecNFTCollection
770    self.CollectionPublicPath = /public/FantastecNFTCollection
771    self.MinterStoragePath = /storage/FantastecNFTMinter
772
773    // Initialize the total supply
774    self.totalSupply = 0
775
776    // Create a Minter resource and save it to storage
777    let minter <- create NFTMinter()
778    let oldMinter <- self.account.storage.load<@NFTMinter>(from: self.MinterStoragePath)
779    self.account.storage.save(<-minter, to: self.MinterStoragePath)
780    destroy oldMinter
781
782    emit ContractInitialized()
783  }
784}
785