@flowtyio/flow-contracts 0.0.18 → 0.1.0-beta.1

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