Smart Contract
BaseNFT
A.befbaccb5032a457.BaseNFT
1import NonFungibleToken from 0x1d7e57aa55817448
2import StringUtils from 0xa340dc0a4ec828ab
3import AddressUtils from 0xa340dc0a4ec828ab
4import ViewResolver from 0x1d7e57aa55817448
5import MetadataViews from 0x1d7e57aa55817448
6import BaseCollection from 0xbefbaccb5032a457
7import FlowtyDrops from 0xbefbaccb5032a457
8import NFTMetadata from 0xbefbaccb5032a457
9import UniversalCollection from 0xbefbaccb5032a457
10
11// A few primary challenges that have come up in thinking about how to define base-level interfaces
12// for collections and NFTs:
13//
14// - How do we resolve contract-level interfaces?
15// - How do we track total supply/serial numbers for NFTs?
16// - How do we store traits and medias?
17//
18// For some of these, mainly contract-level interfaces, we might be able to simply consolidate
19// all of these into one contract interface and require that collection display (banner, thumbnail, name, description, etc.)
20// be stored at the top-level of the contract so that they can be easily referenced later. This could make things easier in that we can
21// make a base definition for anyone to use, but since it isn't a concrete definition, anyone can later override the pre-generated
22// pieces to and modify the code to their liking. This could achieve the best of both worlds where there is minimal work to get something
23// off the ground, but doesn't close the door to customization in the future. This could come at the cost of duplicated resource definitions,
24// or could have the risk of circular imports depending on how we resolve certain pieces of information about a collection.
25access(all) contract interface BaseNFT: ViewResolver {
26 access(all) resource interface NFT: NonFungibleToken.NFT {
27 // This is the id entry that corresponds to an NFTs NFTMetadata.Container entry.
28 // Some NFTs might share the same data, so we want to permit reusing storage where possible
29 access(all) metadataID: UInt64
30
31 access(all) view fun getViews(): [Type] {
32 return [
33 Type<MetadataViews.Display>(),
34 Type<MetadataViews.Serial>(),
35 Type<MetadataViews.Traits>(),
36 Type<MetadataViews.Editions>(),
37 Type<MetadataViews.ExternalURL>(),
38 Type<MetadataViews.NFTCollectionData>(),
39 Type<MetadataViews.NFTCollectionDisplay>()
40 ]
41 }
42
43 // In case the implementor of `NFT` wants to override resolved views,
44 // the actual logic to perform view resolution is done in another method,
45 // with this one calling directly into it.
46 access(all) fun resolveView(_ view: Type): AnyStruct? {
47 return self._resolveView(view)
48 }
49
50 access(all) fun _resolveView(_ view: Type): AnyStruct? {
51 if view == Type<MetadataViews.Serial>() {
52 return MetadataViews.Serial(self.id)
53 }
54
55 let rt = self.getType()
56 let segments = rt.identifier.split(separator: ".")
57 let addr = AddressUtils.parseAddress(rt)!
58 let tmp = getAccount(addr).contracts.borrow<&{BaseCollection}>(name: segments[2])
59 if tmp == nil {
60 return nil
61 }
62
63 let c = tmp!
64 let tmpMd = c.MetadataCap.borrow()
65 if tmpMd == nil {
66 return nil
67 }
68
69 let md = tmpMd!
70 switch view {
71 case Type<MetadataViews.NFTCollectionData>():
72 let pathIdentifier = StringUtils.join([segments[2], segments[1]], "_")
73 return MetadataViews.NFTCollectionData(
74 storagePath: StoragePath(identifier: pathIdentifier)!,
75 publicPath: PublicPath(identifier: pathIdentifier)!,
76 publicCollection: Type<&{NonFungibleToken.Collection}>(),
77 publicLinkedType: Type<&{NonFungibleToken.Collection}>(),
78 createEmptyCollectionFunction: fun(): @{NonFungibleToken.Collection} {
79 let addr = AddressUtils.parseAddress(rt)!
80 let c = getAccount(addr).contracts.borrow<&{BaseCollection}>(name: segments[2])!
81 return <- c.createEmptyCollection(nftType: rt)
82 }
83 )
84 case Type<MetadataViews.NFTCollectionDisplay>():
85 return md.collectionInfo.getDisplay()
86 }
87
88 if let entry = md.borrowMetadata(id: self.metadataID) {
89 switch view {
90 case Type<MetadataViews.Traits>():
91 return entry.getTraits()
92 case Type<MetadataViews.Editions>():
93 return entry.getEditions()
94 case Type<MetadataViews.Display>():
95 let num = (entry.editions?.infoList?.length ?? 0) > 0 ? entry.editions!.infoList[0].number : self.id
96
97 return MetadataViews.Display(
98 name: entry.name.concat(" #").concat(num.toString()),
99 description: entry.description,
100 thumbnail: entry.getThumbnail()
101 )
102 case Type<MetadataViews.ExternalURL>():
103 return entry.getExternalURL()
104 case Type<MetadataViews.Royalties>():
105 return entry.getRoyalties()
106 }
107 }
108
109 return nil
110 }
111
112 access(all) fun createEmptyCollection(): @{NonFungibleToken.Collection} {
113 return <- UniversalCollection.createCollection(nftType: self.getType())
114 }
115 }
116}