Smart Contract
MetadataViews
A.3eebe1cb4a1126b2.MetadataViews
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