Smart Contract

MetadataViews

A.3eebe1cb4a1126b2.MetadataViews

Valid From

122,288,389

Deployed

6d ago
Feb 22, 2026, 10:50:56 AM UTC

Dependents

0 imports
1import FungibleToken from 0xf233dcee88fe0abe
2import NonFungibleToken from 0x1d7e57aa55817448
3import ViewResolver from 0x1d7e57aa55817448
4
5/// This contract implements the metadata standard proposed
6/// in FLIP-0636.
7///
8/// Ref: https://github.com/onflow/flips/blob/main/application/20210916-nft-metadata.md
9///
10/// Structs and resources can implement one or more
11/// metadata types, called views. Each view type represents
12/// a different kind of metadata, such as a creator biography
13/// or a JPEG image file.
14///
15access(all) contract MetadataViews {
16
17    /// Function to resolve a contract view based on a type identifier String
18    /// and view type. Borrows the contract as &{ViewResolver} and 
19    /// then calls resolveContractView for the specified type and view.
20    ///
21    /// @param resourceTypeIdentifier: The type identifier of the resource
22    /// @param viewType: The Type of the desired view.
23    /// @return A structure representing the requested view. If anything failed, returns nil
24    ///
25    access(all) fun resolveContractViewFromTypeIdentifier(
26        resourceTypeIdentifier: String,
27        viewType: Type
28    ): AnyStruct? {
29        if let resourceType = CompositeType(resourceTypeIdentifier) {
30            if let viewResolverRef = getAccount(resourceType.address!).contracts.borrow<&{ViewResolver}>(
31                name: resourceType.contractName!
32            ) {
33                return viewResolverRef.resolveContractView(resourceType: resourceType, viewType: viewType)
34            } else {
35                return nil
36            }
37        } else {
38            return nil
39        }
40    }
41
42
43    /// Display is a basic view that includes the name, description and
44    /// thumbnail for an object. Most objects should implement this view.
45    ///
46    access(all) struct Display {
47
48        /// The name of the object.
49        ///
50        /// This field will be displayed in lists and therefore should
51        /// be short an concise.
52        ///
53        access(all) let name: String
54
55        /// A written description of the object.
56        ///
57        /// This field will be displayed in a detailed view of the object,
58        /// so can be more verbose (e.g. a paragraph instead of a single line).
59        ///
60        access(all) let description: String
61
62        /// A small thumbnail representation of the object.
63        ///
64        /// This field should be a web-friendly file (i.e JPEG, PNG)
65        /// that can be displayed in lists, link previews, etc.
66        ///
67        access(all) let thumbnail: {File}
68
69        view init(
70            name: String,
71            description: String,
72            thumbnail: {File}
73        ) {
74            self.name = name
75            self.description = description
76            self.thumbnail = thumbnail
77        }
78    }
79
80    /// Helper to get Display in a typesafe way
81    ///
82    /// @param viewResolver: A reference to the resolver resource
83    /// @return An optional Display struct
84    ///
85    access(all) fun getDisplay(_ viewResolver: &{ViewResolver.Resolver}) : Display? {
86        if let view = viewResolver.resolveView(Type<Display>()) {
87            if let v = view as? Display {
88                return v
89            }
90        }
91        return nil
92    }
93
94    /// Generic interface that represents a file stored on or off chain. Files
95    /// can be used to references images, videos and other media.
96    ///
97    access(all) struct interface File {
98        access(all) view fun uri(): String
99    }
100
101    /// View to expose a file that is accessible at an HTTP (or HTTPS) URL.
102    ///
103    access(all) struct HTTPFile: File {
104        access(all) let url: String
105
106        view init(url: String) {
107            self.url = url
108        }
109
110        access(all) view fun uri(): String {
111            return self.url
112        }
113    }
114
115    /// View to expose a file stored on IPFS.
116    /// IPFS images are referenced by their content identifier (CID)
117    /// rather than a direct URI. A client application can use this CID
118    /// to find and load the image via an IPFS gateway.
119    ///
120    access(all) struct IPFSFile: File {
121
122        /// CID is the content identifier for this IPFS file.
123        ///
124        /// Ref: https://docs.ipfs.io/concepts/content-addressing/
125        ///
126        access(all) let cid: String
127
128        /// Path is an optional path to the file resource in an IPFS directory.
129        ///
130        /// This field is only needed if the file is inside a directory.
131        ///
132        /// Ref: https://docs.ipfs.io/concepts/file-systems/
133        ///
134        access(all) let path: String?
135
136        view init(cid: String, path: String?) {
137            self.cid = cid
138            self.path = path
139        }
140
141        /// This function returns the IPFS native URL for this file.
142        /// Ref: https://docs.ipfs.io/how-to/address-ipfs-on-web/#native-urls
143        ///
144        /// @return The string containing the file uri
145        ///
146        access(all) view fun uri(): String {
147            if let path = self.path {
148                return "ipfs://\(self.cid)/\(path)"
149            }
150
151            return "ipfs://\(self.cid)"
152        }
153    }
154
155    /// A struct to represent a generic URI. May be used to represent the URI of
156    /// the NFT where the type of URI is not able to be determined (i.e. HTTP,
157    /// IPFS, etc.)
158    ///
159    access(all) struct URI: File {
160        /// The base URI prefix, if any. Not needed for all URIs, but helpful
161        /// for some use cases For example, updating a whole NFT collection's
162        /// image host easily
163        ///
164        access(all) let baseURI: String?
165        /// The URI string value
166        /// NOTE: this is set on init as a concatenation of the baseURI and the
167        /// value if baseURI != nil
168        ///
169        access(self) let value: String
170
171        access(all) view fun uri(): String {
172            return self.value
173        }
174
175        init(baseURI: String?, value: String) {
176            self.baseURI = baseURI
177            self.value = baseURI != nil ? baseURI!.concat(value) : value
178        }
179    }
180
181    access(all) struct Media {
182
183        /// File for the media
184        ///
185        access(all) let file: {File}
186
187        /// media-type comes on the form of type/subtype as described here 
188        /// https://developer.mozilla.org/en-US/docs/Web/HTTP/Basics_of_HTTP/MIME_types
189        ///
190        access(all) let mediaType: String
191
192        view init(file: {File}, mediaType: String) {
193          self.file=file
194          self.mediaType=mediaType
195        }
196    }
197
198    /// Wrapper view for multiple media views
199    ///
200    access(all) struct Medias {
201
202        /// An arbitrary-sized list for any number of Media items
203        access(all) let items: [Media]
204
205        view init(_ items: [Media]) {
206            self.items = items
207        }
208    }
209
210    /// Helper to get Medias in a typesafe way
211    ///
212    /// @param viewResolver: A reference to the resolver resource
213    /// @return A optional Medias struct
214    ///
215    access(all) fun getMedias(_ viewResolver: &{ViewResolver.Resolver}) : Medias? {
216        if let view = viewResolver.resolveView(Type<Medias>()) {
217            if let v = view as? Medias {
218                return v
219            }
220        }
221        return nil
222    }
223
224    /// View to represent a license according to https://spdx.org/licenses/
225    /// This view can be used if the content of an NFT is licensed.
226    ///
227    access(all) struct License {
228        access(all) let spdxIdentifier: String
229
230        view init(_ identifier: String) {
231            self.spdxIdentifier = identifier
232        }
233    }
234
235    /// Helper to get License in a typesafe way
236    ///
237    /// @param viewResolver: A reference to the resolver resource
238    /// @return An optional License struct
239    ///
240    access(all) fun getLicense(_ viewResolver: &{ViewResolver.Resolver}) : License? {
241        if let view = viewResolver.resolveView(Type<License>()) {
242            if let v = view as? License {
243                return v
244            }
245        }
246        return nil
247    }
248
249    /// View to expose a URL to this item on an external site.
250    /// This can be used by applications like .find and Blocto to direct users 
251    /// to the original link for an NFT or a project page that describes the NFT collection.
252    /// eg https://www.my-nft-project.com/overview-of-nft-collection
253    ///
254    access(all) struct ExternalURL {
255        access(all) let url: String
256
257        view init(_ url: String) {
258            self.url=url
259        }
260    }
261
262    /// Helper to get ExternalURL in a typesafe way
263    ///
264    /// @param viewResolver: A reference to the resolver resource
265    /// @return An optional ExternalURL struct
266    ///
267    access(all) fun getExternalURL(_ viewResolver: &{ViewResolver.Resolver}) : ExternalURL? {
268        if let view = viewResolver.resolveView(Type<ExternalURL>()) {
269            if let v = view as? ExternalURL {
270                return v
271            }
272        }
273        return nil
274    }
275
276    /// View that defines the composable royalty standard that gives marketplaces a 
277    /// unified interface to support NFT royalties.
278    ///
279    access(all) struct Royalty {
280
281        /// Generic FungibleToken Receiver for the beneficiary of the royalty
282        /// Can get the concrete type of the receiver with receiver.getType()
283        /// Recommendation - Users should create a new link for a FlowToken 
284        /// receiver for this using `getRoyaltyReceiverPublicPath()`, and not 
285        /// use the default FlowToken receiver. This will allow users to update 
286        /// the capability in the future to use a more generic capability
287        access(all) let receiver: Capability<&{FungibleToken.Receiver}>
288
289        /// Multiplier used to calculate the amount of sale value transferred to 
290        /// royalty receiver. Note - It should be between 0.0 and 1.0 
291        /// Ex - If the sale value is x and multiplier is 0.56 then the royalty 
292        /// value would be 0.56 * x.
293        /// Generally percentage get represented in terms of basis points
294        /// in solidity based smart contracts while cadence offers `UFix64` 
295        /// that already supports the basis points use case because its 
296        /// operations are entirely deterministic integer operations and support 
297        /// up to 8 points of precision.
298        access(all) let cut: UFix64
299
300        /// Optional description: This can be the cause of paying the royalty,
301        /// the relationship between the `wallet` and the NFT, or anything else
302        /// that the owner might want to specify.
303        access(all) let description: String
304
305        view init(receiver: Capability<&{FungibleToken.Receiver}>, cut: UFix64, description: String) {
306            pre {
307                cut >= 0.0 && cut <= 1.0 :
308                    "MetadataViews.Royalty.init: Cannot initialize the Royalty Metadata View! "
309                    .concat("The provided royalty cut value of \(cut) is invalid. ")
310                    .concat("It should be within the valid range between 0 and 1. i.e [0,1]")
311            }
312            self.receiver = receiver
313            self.cut = cut
314            self.description = description
315        }
316    }
317
318    /// Wrapper view for multiple Royalty views.
319    /// Marketplaces can query this `Royalties` struct from NFTs 
320    /// and are expected to pay royalties based on these specifications.
321    ///
322    access(all) struct Royalties {
323
324        /// Array that tracks the individual royalties
325        access(self) let cutInfos: [Royalty]
326
327        access(all) view init(_ cutInfos: [Royalty]) {
328            // Validate that sum of all cut multipliers should not be greater than 1.0
329            var totalCut = 0.0
330            for royalty in cutInfos {
331                totalCut = totalCut + royalty.cut
332            }
333            assert(
334                totalCut <= 1.0,
335                message:
336                    "MetadataViews.Royalties.init: Cannot initialize Royalties Metadata View! "
337                    .concat(" The sum of cutInfos multipliers is \(totalCut) but it should not be greater than 1.0")
338            )
339            // Assign the cutInfos
340            self.cutInfos = cutInfos
341        }
342
343        /// Return the cutInfos list
344        ///
345        /// @return An array containing all the royalties structs
346        ///
347        access(all) view fun getRoyalties(): [Royalty] {
348            return self.cutInfos
349        }
350    }
351
352    /// Helper to get Royalties in a typesafe way
353    ///
354    /// @param viewResolver: A reference to the resolver resource
355    /// @return A optional Royalties struct
356    ///
357    access(all) fun getRoyalties(_ viewResolver: &{ViewResolver.Resolver}) : Royalties? {
358        if let view = viewResolver.resolveView(Type<Royalties>()) {
359            if let v = view as? Royalties {
360                return v
361            }
362        }
363        return nil
364    }
365
366    /// Get the path that should be used for receiving royalties
367    /// This is a path that will eventually be used for a generic switchboard receiver,
368    /// hence the name but will only be used for royalties for now.
369    ///
370    /// @return The PublicPath for the generic FT receiver
371    ///
372    access(all) view fun getRoyaltyReceiverPublicPath(): PublicPath {
373        return /public/GenericFTReceiver
374    }
375
376    /// View to represent a single field of metadata on an NFT.
377    /// This is used to get traits of individual key/value pairs along with some
378    /// contextualized data about the trait
379    ///
380    access(all) struct Trait {
381        // The name of the trait. Like Background, Eyes, Hair, etc.
382        access(all) let name: String
383
384        // The underlying value of the trait, the rest of the fields of a trait provide context to the value.
385        access(all) let value: AnyStruct
386
387        // displayType is used to show some context about what this name and value represent
388        // for instance, you could set value to a unix timestamp, and specify displayType as "Date" to tell
389        // platforms to consume this trait as a date and not a number
390        access(all) let displayType: String?
391
392        // Rarity can also be used directly on an attribute.
393        //
394        // This is optional because not all attributes need to contribute to the NFT's rarity.
395        access(all) let rarity: Rarity?
396
397        view init(name: String, value: AnyStruct, displayType: String?, rarity: Rarity?) {
398            self.name = name
399            self.value = value
400            self.displayType = displayType
401            self.rarity = rarity
402        }
403    }
404
405    /// Wrapper view to return all the traits on an NFT.
406    /// This is used to return traits as individual key/value pairs along with
407    /// some contextualized data about each trait.
408    access(all) struct Traits {
409        access(all) let traits: [Trait]
410
411        view init(_ traits: [Trait]) {
412            self.traits = traits
413        }
414            
415        /// Adds a single Trait to the Traits view
416        /// 
417        /// @param Trait: The trait struct to be added
418        ///
419        access(all) fun addTrait(_ t: Trait) {
420            self.traits.append(t)
421        }
422    }
423
424    /// Helper to get Traits view in a typesafe way
425    ///
426    /// @param viewResolver: A reference to the resolver resource
427    /// @return A optional Traits struct
428    ///
429    access(all) fun getTraits(_ viewResolver: &{ViewResolver.Resolver}) : Traits? {
430        if let view = viewResolver.resolveView(Type<Traits>()) {
431            if let v = view as? Traits {
432                return v
433            }
434        }
435        return nil
436    }
437
438    /// Helper function to easily convert a dictionary to traits. For NFT 
439    /// collections that do not need either of the optional values of a Trait, 
440    /// this method should suffice to give them an array of valid traits.
441    ///
442    /// @param dict: The dictionary to be converted to Traits
443    /// @param excludedNames: An optional String array specifying the `dict`
444    ///         keys that are not wanted to become `Traits`
445    /// @return The generated Traits view
446    ///
447    access(all) fun dictToTraits(dict: {String: AnyStruct}, excludedNames: [String]?): Traits {
448        // Collection owners might not want all the fields in their metadata included.
449        // They might want to handle some specially, or they might just not want them included at all.
450        if excludedNames != nil {
451            for k in excludedNames! {
452                dict.remove(key: k)
453            }
454        }
455
456        let traits: [Trait] = []
457        for k in dict.keys {
458            let trait = Trait(name: k, value: dict[k]!, displayType: nil, rarity: nil)
459            traits.append(trait)
460        }
461
462        return Traits(traits)
463    }
464
465    /// Optional view for collections that issue multiple objects
466    /// with the same or similar metadata, for example an X of 100 set. This
467    /// information is useful for wallets and marketplaces.
468    /// An NFT might be part of multiple editions, which is why the edition
469    /// information is returned as an arbitrary sized array
470    ///
471    access(all) struct Edition {
472
473        /// The name of the edition
474        /// For example, this could be Set, Play, Series,
475        /// or any other way a project could classify its editions
476        access(all) let name: String?
477
478        /// The edition number of the object.
479        /// For an "24 of 100 (#24/100)" item, the number is 24.
480        access(all) let number: UInt64
481
482        /// The max edition number of this type of objects.
483        /// This field should only be provided for limited-editioned objects.
484        /// For an "24 of 100 (#24/100)" item, max is 100.
485        /// For an item with unlimited edition, max should be set to nil.
486        ///
487        access(all) let max: UInt64?
488
489        view init(name: String?, number: UInt64, max: UInt64?) {
490            if max != nil {
491                assert(
492                    number <= max!,
493                    message:
494                        "MetadataViews.Edition.init: Cannot intialize the Edition Metadata View! "
495                        .concat("The provided edition number of \(number) cannot be greater than the max edition number of \(max!).")
496                )
497            }
498            self.name = name
499            self.number = number
500            self.max = max
501        }
502    }
503
504    /// Wrapper view for multiple Edition views
505    ///
506    access(all) struct Editions {
507
508        /// An arbitrary-sized list for any number of editions
509        /// that the NFT might be a part of
510        access(all) let infoList: [Edition]
511
512        view init(_ infoList: [Edition]) {
513            self.infoList = infoList
514        }
515    }
516
517    /// Helper to get Editions in a typesafe way
518    ///
519    /// @param viewResolver: A reference to the resolver resource
520    /// @return An optional Editions struct
521    ///
522    access(all) fun getEditions(_ viewResolver: &{ViewResolver.Resolver}) : Editions? {
523        if let view = viewResolver.resolveView(Type<Editions>()) {
524            if let v = view as? Editions {
525                return v
526            }
527        }
528        return nil
529    }
530
531    /// View representing a project-defined serial number for a specific NFT
532    /// Projects have different definitions for what a serial number should be
533    /// Some may use the NFTs regular ID and some may use a different
534    /// classification system. The serial number is expected to be unique among
535    /// other NFTs within that project
536    ///
537    access(all) struct Serial {
538        access(all) let number: UInt64
539
540        view init(_ number: UInt64) {
541            self.number = number
542        }
543    }
544
545    /// Helper to get Serial in a typesafe way
546    ///
547    /// @param viewResolver: A reference to the resolver resource
548    /// @return An optional Serial struct
549    ///
550    access(all) fun getSerial(_ viewResolver: &{ViewResolver.Resolver}) : Serial? {
551        if let view = viewResolver.resolveView(Type<Serial>()) {
552            if let v = view as? Serial {
553                return v
554            }
555        }
556        return nil
557    }
558
559    /// View to expose rarity information for a single rarity
560    /// Note that a rarity needs to have either score or description but it can 
561    /// have both
562    ///
563    access(all) struct Rarity {
564        /// The score of the rarity as a number
565        access(all) let score: UFix64?
566
567        /// The maximum value of score
568        access(all) let max: UFix64?
569
570        /// The description of the rarity as a string.
571        ///
572        /// This could be Legendary, Epic, Rare, Uncommon, Common or any other string value
573        access(all) let description: String?
574
575        view init(score: UFix64?, max: UFix64?, description: String?) {
576            if score == nil && description == nil {
577                panic("MetadataViews.Rarity.init: Cannot initialize the Rarity Metadata View! "
578                      .concat("The provided score and description are both `nil`. A Rarity needs to set score, description, or both"))
579            }
580
581            self.score = score
582            self.max = max
583            self.description = description
584        }
585    }
586
587    /// Helper to get Rarity view in a typesafe way
588    ///
589    /// @param viewResolver: A reference to the resolver resource
590    /// @return A optional Rarity struct
591    ///
592    access(all) fun getRarity(_ viewResolver: &{ViewResolver.Resolver}) : Rarity? {
593        if let view = viewResolver.resolveView(Type<Rarity>()) {
594            if let v = view as? Rarity {
595                return v
596            }
597        }
598        return nil
599    }
600
601    /// NFTView wraps all Core views along `id` and `uuid` fields, and is used 
602    /// to give a complete picture of an NFT. Most NFTs should implement this 
603    /// view.
604    ///
605    access(all) struct NFTView {
606        access(all) let id: UInt64
607        access(all) let uuid: UInt64
608        access(all) let display: MetadataViews.Display?
609        access(all) let externalURL: MetadataViews.ExternalURL?
610        access(all) let collectionData: NFTCollectionData?
611        access(all) let collectionDisplay: NFTCollectionDisplay?
612        access(all) let royalties: Royalties?
613        access(all) let traits: Traits?
614
615        view init(
616            id : UInt64,
617            uuid : UInt64,
618            display : MetadataViews.Display?,
619            externalURL : MetadataViews.ExternalURL?,
620            collectionData : NFTCollectionData?,
621            collectionDisplay : NFTCollectionDisplay?,
622            royalties : Royalties?,
623            traits: Traits?
624        ) {
625            self.id = id
626            self.uuid = uuid
627            self.display = display
628            self.externalURL = externalURL
629            self.collectionData = collectionData
630            self.collectionDisplay = collectionDisplay
631            self.royalties = royalties
632            self.traits = traits
633        }
634    }
635
636    /// Helper to get an NFT view 
637    ///
638    /// @param id: The NFT id
639    /// @param viewResolver: A reference to the resolver resource
640    /// @return A NFTView struct
641    ///
642    access(all) fun getNFTView(id: UInt64, viewResolver: &{ViewResolver.Resolver}) : NFTView {
643        let nftView = viewResolver.resolveView(Type<NFTView>())
644        if nftView != nil {
645            return nftView! as! NFTView
646        }
647
648        return NFTView(
649            id : id,
650            uuid: viewResolver.uuid,
651            display: MetadataViews.getDisplay(viewResolver),
652            externalURL : MetadataViews.getExternalURL(viewResolver),
653            collectionData : self.getNFTCollectionData(viewResolver),
654            collectionDisplay : self.getNFTCollectionDisplay(viewResolver),
655            royalties : self.getRoyalties(viewResolver),
656            traits : self.getTraits(viewResolver)
657        )
658    }
659
660    /// View to expose the information needed store and retrieve an NFT.
661    /// This can be used by applications to setup a NFT collection with proper 
662    /// storage and public capabilities.
663    ///
664    access(all) struct NFTCollectionData {
665        /// Path in storage where this NFT is recommended to be stored.
666        access(all) let storagePath: StoragePath
667
668        /// Public path which must be linked to expose public capabilities of this NFT
669        /// including standard NFT interfaces and metadataviews interfaces
670        access(all) let publicPath: PublicPath
671
672        /// The concrete type of the collection that is exposed to the public
673        /// now that entitlements exist, it no longer needs to be restricted to a specific interface
674        access(all) let publicCollection: Type
675
676        /// Type that should be linked at the aforementioned public path
677        access(all) let publicLinkedType: Type
678
679        /// Function that allows creation of an empty NFT collection that is intended to store
680        /// this NFT.
681        access(all) let createEmptyCollection: fun(): @{NonFungibleToken.Collection}
682
683        view init(
684            storagePath: StoragePath,
685            publicPath: PublicPath,
686            publicCollection: Type,
687            publicLinkedType: Type,
688            createEmptyCollectionFunction: fun(): @{NonFungibleToken.Collection}
689        ) {
690            pre {
691                publicLinkedType.isSubtype(of: Type<&{NonFungibleToken.Collection}>()):
692                    "MetadataViews.NFTCollectionData.init: Cannot initialize the NFTCollectionData Metadata View! "
693                    .concat("The Public linked type <\(publicLinkedType.identifier)> is incorrect. It must be a subtype of the NonFungibleToken.Collection interface.")
694            }
695            self.storagePath=storagePath
696            self.publicPath=publicPath
697            self.publicCollection=publicCollection
698            self.publicLinkedType=publicLinkedType
699            self.createEmptyCollection=createEmptyCollectionFunction
700        }
701    }
702
703    /// Helper to get NFTCollectionData in a way that will return an typed Optional
704    ///
705    /// @param viewResolver: A reference to the resolver resource
706    /// @return A optional NFTCollectionData struct
707    ///
708    access(all) fun getNFTCollectionData(_ viewResolver: &{ViewResolver.Resolver}) : NFTCollectionData? {
709        if let view = viewResolver.resolveView(Type<NFTCollectionData>()) {
710            if let v = view as? NFTCollectionData {
711                return v
712            }
713        }
714        return nil
715    }
716
717    /// View to expose the information needed to showcase this NFT's
718    /// collection. This can be used by applications to give an overview and 
719    /// graphics of the NFT collection this NFT belongs to.
720    ///
721    access(all) struct NFTCollectionDisplay {
722        // Name that should be used when displaying this NFT collection.
723        access(all) let name: String
724
725        // Description that should be used to give an overview of this collection.
726        access(all) let description: String
727
728        // External link to a URL to view more information about this collection.
729        access(all) let externalURL: MetadataViews.ExternalURL
730
731        // Square-sized image to represent this collection.
732        access(all) let squareImage: MetadataViews.Media
733
734        // Banner-sized image for this collection, recommended to have a size near 1400x350.
735        access(all) let bannerImage: MetadataViews.Media
736
737        // Social links to reach this collection's social homepages.
738        // Possible keys may be "instagram", "twitter", "discord", etc.
739        access(all) let socials: {String: MetadataViews.ExternalURL}
740
741        view init(
742            name: String,
743            description: String,
744            externalURL: MetadataViews.ExternalURL,
745            squareImage: MetadataViews.Media,
746            bannerImage: MetadataViews.Media,
747            socials: {String: MetadataViews.ExternalURL}
748        ) {
749            self.name = name
750            self.description = description
751            self.externalURL = externalURL
752            self.squareImage = squareImage
753            self.bannerImage = bannerImage
754            self.socials = socials
755        }
756    }
757
758    /// Helper to get NFTCollectionDisplay in a way that will return a typed 
759    /// Optional
760    ///
761    /// @param viewResolver: A reference to the resolver resource
762    /// @return A optional NFTCollection struct
763    ///
764    access(all) fun getNFTCollectionDisplay(_ viewResolver: &{ViewResolver.Resolver}) : NFTCollectionDisplay? {
765        if let view = viewResolver.resolveView(Type<NFTCollectionDisplay>()) {
766            if let v = view as? NFTCollectionDisplay {
767                return v
768            }
769        }
770        return nil
771    }
772    /// This view may be used by Cadence-native projects to define their
773    /// contract- and token-level metadata according to EVM-compatible formats.
774    /// Several ERC standards (e.g. ERC20, ERC721, etc.) expose name and symbol
775    /// values to define assets as well as contract- & token-level metadata view
776    /// `tokenURI(uint256)` and `contractURI()` methods. This view enables
777    /// Cadence projects to define in their own contracts how they would like
778    /// their metadata to be defined when bridged to EVM.
779    ///
780    access(all) struct EVMBridgedMetadata {
781
782        /// The name of the asset
783        ///
784        access(all) let name: String
785
786        /// The symbol of the asset
787        ///
788        access(all) let symbol: String
789
790        /// The URI of the asset - this can either be contract-level or
791        /// token-level URI depending on where the metadata is resolved. It
792        /// is recommended to reference EVM metadata standards for how to best
793        /// prepare your view's formatted value.
794        ///
795        /// For example, while you may choose to take advantage of onchain
796        /// metadata, as is the case for most Cadence NFTs, you may also choose
797        /// to represent your asset's metadata in IPFS and assign this value as
798        /// an IPFSFile struct pointing to that IPFS file. Alternatively, you
799        /// may serialize your NFT's metadata and assign it as a JSON string
800        /// data URL representating the NFT's onchain metadata at the time this
801        /// view is resolved.
802        ///
803        access(all) let uri: {File}
804
805        init(name: String, symbol: String, uri: {File}) {
806            self.name = name
807            self.symbol = symbol
808            self.uri = uri
809        }
810    }
811
812    access(all) fun getEVMBridgedMetadata(_ viewResolver: &{ViewResolver.Resolver}) : EVMBridgedMetadata? {
813        if let view = viewResolver.resolveView(Type<EVMBridgedMetadata>()) {
814            if let v = view as? EVMBridgedMetadata {
815                return v
816            }
817        }
818        return nil
819    }
820
821}
822