Smart Contract
StarlyMetadata
A.5b82f21c0edf76e3.StarlyMetadata
1import FungibleToken from 0xf233dcee88fe0abe
2import MetadataViews from 0x1d7e57aa55817448
3import StarlyCollectorScore from 0x5b82f21c0edf76e3
4import StarlyMetadataViews from 0x5b82f21c0edf76e3
5import StarlyIDParser from 0x5b82f21c0edf76e3
6
7access(all) contract StarlyMetadata {
8
9 access(all) struct CollectionMetadata {
10 access(all) let collection: StarlyMetadataViews.Collection
11 access(all) let cards: {UInt32: StarlyMetadataViews.Card}
12
13 init(
14 collection: StarlyMetadataViews.Collection,
15 cards: {UInt32: StarlyMetadataViews.Card}) {
16
17 self.collection = collection
18 self.cards = cards
19 }
20
21 access(all) fun insertCard(cardID: UInt32, card: StarlyMetadataViews.Card) {
22 self.cards.insert(key: cardID, card)
23 }
24
25 access(all) fun removeCard(cardID: UInt32) {
26 self.cards.remove(key: cardID)
27 }
28 }
29
30 access(contract) var metadata: {String: CollectionMetadata}
31
32 access(all) let AdminStoragePath: StoragePath
33 access(all) let EditorStoragePath: StoragePath
34 access(all) let EditorProxyStoragePath: StoragePath
35 access(all) let EditorProxyPublicPath: PublicPath
36
37 access(all) view fun getViews(): [Type] {
38 return [
39 Type<MetadataViews.Display>(),
40 Type<MetadataViews.Edition>(),
41 Type<MetadataViews.Royalties>(),
42 Type<MetadataViews.ExternalURL>(),
43 Type<MetadataViews.Traits>(),
44 Type<MetadataViews.NFTCollectionDisplay>(),
45 Type<MetadataViews.NFTCollectionData>(),
46 Type<StarlyMetadataViews.CardEdition>()
47 ]
48 }
49
50 access(all) fun resolveView(starlyID: String, view: Type): AnyStruct? {
51 switch view {
52 case Type<MetadataViews.Display>():
53 return self.getDisplay(starlyID: starlyID)
54 case Type<MetadataViews.Edition>():
55 return self.getEdition(starlyID: starlyID)
56 case Type<MetadataViews.Royalties>():
57 return self.getRoyalties(starlyID: starlyID)
58 case Type<MetadataViews.ExternalURL>():
59 return self.getExternalURL(starlyID: starlyID)
60 case Type<MetadataViews.Traits>():
61 return self.getTraits(starlyID: starlyID)
62 case Type<MetadataViews.NFTCollectionDisplay>():
63 return self.getNFTCollectionDisplay()
64 case Type<StarlyMetadataViews.CardEdition>():
65 return self.getCardEdition(starlyID: starlyID)
66 }
67 return nil
68 }
69
70 access(all) fun getDisplay(starlyID: String): MetadataViews.Display? {
71 if let cardEdition = self.getCardEdition(starlyID: starlyID) {
72 let card = cardEdition.card
73 let title = card.title
74 let edition = cardEdition.edition.toString()
75 let editions = card.editions.toString()
76 let creatorName = cardEdition.collection.creator.name
77
78 var thumbnail: String? = ""
79 let mediaSize = cardEdition.card.mediaSizes[0]
80 if mediaSize.screenshot != nil {
81 thumbnail = mediaSize.screenshot
82 } else {
83 thumbnail = mediaSize.url
84 }
85
86 return MetadataViews.Display(
87 name: title.concat(" #").concat(edition).concat("/").concat(editions).concat(" by ").concat(creatorName),
88 description: cardEdition.card.description,
89 thumbnail: MetadataViews.HTTPFile(url:thumbnail!)
90 )
91 }
92 return nil
93 }
94
95 access(all) fun getEdition(starlyID: String): MetadataViews.Edition? {
96 if let cardEdition = self.getCardEdition(starlyID: starlyID) {
97 let card = cardEdition.card
98 let edition = cardEdition.edition
99 let editions = card.editions
100 return MetadataViews.Edition(
101 name: "Card",
102 number: UInt64(edition),
103 max: UInt64(editions)
104 )
105 }
106 return nil
107 }
108
109 access(all) fun getRoyalties(starlyID: String): MetadataViews.Royalties? {
110 if let cardEdition = self.getCardEdition(starlyID: starlyID) {
111 let creator = cardEdition.collection.creator
112 let royalties : [MetadataViews.Royalty] = [
113 MetadataViews.Royalty(
114 receiver: getAccount(0x12c122ca9266c278).capabilities.get<&{FungibleToken.Receiver}>(/public/flowTokenReceiver)!,
115 cut: 0.05,
116 description: "Starly royalty (5%)"
117 ),
118 MetadataViews.Royalty(
119 receiver: getAccount(creator.address!).capabilities.get<&{FungibleToken.Receiver}>(/public/flowTokenReceiver)!,
120 cut: 0.05,
121 description: "Creator royalty (%5) for ".concat(creator.username)
122 )
123 ]
124 return MetadataViews.Royalties(royalties)
125 }
126 return nil
127 }
128
129 access(all) fun getExternalURL(starlyID: String): MetadataViews.ExternalURL? {
130 if let cardEdition = self.getCardEdition(starlyID: starlyID) {
131 return MetadataViews.ExternalURL(cardEdition.url)
132 }
133 return nil
134 }
135
136 access(all) fun getTraits(starlyID: String): MetadataViews.Traits? {
137 if let cardEdition = self.getCardEdition(starlyID: starlyID) {
138 let collection = cardEdition.collection
139 let creator = collection.creator
140 let card = cardEdition.card
141 return MetadataViews.Traits([
142 MetadataViews.Trait(name:"Name", value: card.title, displayType: "String", rarity: nil),
143 MetadataViews.Trait(name:"Description", value: card.description, displayType: "String", rarity: nil),
144 MetadataViews.Trait(name:"Rarity", value: card.rarity, displayType: "String", rarity: nil),
145 MetadataViews.Trait(name:"Collection (Name)", value: collection.title, displayType: "String", rarity: nil),
146 MetadataViews.Trait(name:"Collection (URL)", value: collection.url, displayType: "String", rarity: nil),
147 MetadataViews.Trait(name:"Creator (Name)", value: creator.name, displayType: "String", rarity: nil),
148 MetadataViews.Trait(name:"Creator (Username)", value: creator.username, displayType: "String", rarity: nil),
149 MetadataViews.Trait(name:"Creator (URL)", value: creator.url, displayType: "String", rarity: nil),
150 MetadataViews.Trait(name:"Collector Score", value: cardEdition.score ?? 0.0, displayType: "Numeric", rarity: nil),
151 MetadataViews.Trait(name:"URL", value: cardEdition.url, displayType: "String", rarity: nil),
152 MetadataViews.Trait(name:"Preview URL", value: cardEdition.previewUrl, displayType: "String", rarity: nil)
153 ])
154 }
155 return nil
156 }
157
158 access(all) fun getNFTCollectionDisplay(): MetadataViews.NFTCollectionDisplay {
159 return MetadataViews.NFTCollectionDisplay(
160 name: "Starly",
161 description: "Starly is a launchpad and marketplace for gamified NFT collections on Flow.",
162 externalURL: MetadataViews.ExternalURL("https://starly.io"),
163 squareImage: MetadataViews.Media(
164 file: MetadataViews.HTTPFile(
165 url: "https://storage.googleapis.com/starly-prod.appspot.com/assets/starly-square-logo.jpg"
166 ),
167 mediaType: "image/jpeg"
168 ),
169 bannerImage: MetadataViews.Media(
170 file: MetadataViews.HTTPFile(
171 url: "https://storage.googleapis.com/starly-prod.appspot.com/assets/starly-banner.jpg"
172 ),
173 mediaType: "image/jpeg"
174 ),
175 socials: {
176 "twitter": MetadataViews.ExternalURL("https://twitter.com/StarlyNFT"),
177 "discord": MetadataViews.ExternalURL("https://discord.gg/starly"),
178 "medium": MetadataViews.ExternalURL("https://medium.com/@StarlyNFT")
179 }
180 )
181 }
182
183 access(all) fun getCardEdition(starlyID: String): StarlyMetadataViews.CardEdition? {
184 let starlyID = StarlyIDParser.parse(starlyID: starlyID)
185 let collectionMetadataOptional = self.metadata[starlyID.collectionID]
186 if let collectionMetadata = collectionMetadataOptional {
187 let cardOptional = collectionMetadata.cards[starlyID.cardID]
188 if let card = cardOptional {
189 return StarlyMetadataViews.CardEdition(
190 collection: collectionMetadata.collection,
191 card: card,
192 edition: starlyID.edition,
193 score: StarlyCollectorScore.getCollectorScore(
194 collectionID: starlyID.collectionID,
195 rarity: card.rarity,
196 edition: starlyID.edition,
197 editions: card.editions,
198 priceCoefficient: collectionMetadata.collection.priceCoefficient
199 ),
200 url: card.url.concat("/").concat(starlyID.edition.toString()),
201 previewUrl: card.previewUrl.concat("/").concat(starlyID.edition.toString())
202 )
203 }
204 }
205 return nil
206 }
207
208 access(all) resource interface IEditor {
209 access(all) fun putCollectionCard(collectionID: String, cardID: UInt32, card: StarlyMetadataViews.Card)
210 access(all) fun putMetadata(collectionID: String, metadata: CollectionMetadata)
211 access(all) fun deleteCollectionCard(collectionID: String, cardID: UInt32)
212 access(all) fun deleteMetadata(collectionID: String)
213 }
214
215 access(all) resource Editor: IEditor {
216 access(all) fun putCollectionCard(collectionID: String, cardID: UInt32, card: StarlyMetadataViews.Card) {
217 StarlyMetadata.metadata[collectionID]?.insertCard(cardID: cardID, card: card)
218 }
219
220 access(all) fun putMetadata(collectionID: String, metadata: CollectionMetadata) {
221 StarlyMetadata.metadata.insert(key: collectionID, metadata)
222 }
223
224 access(all) fun deleteCollectionCard(collectionID: String, cardID: UInt32) {
225 StarlyMetadata.metadata[collectionID]?.removeCard(cardID: cardID)
226 }
227
228 access(all) fun deleteMetadata(collectionID: String) {
229 StarlyMetadata.metadata.remove(key: collectionID)
230 }
231 }
232
233 access(all) resource interface EditorProxyPublic {
234 access(all) fun setEditorCapability(cap: Capability<&Editor>)
235 }
236
237 access(all) resource EditorProxy: IEditor, EditorProxyPublic {
238 access(self) var editorCapability: Capability<&Editor>?
239
240 access(all) fun setEditorCapability(cap: Capability<&Editor>) {
241 self.editorCapability = cap
242 }
243
244 access(all) fun putCollectionCard(collectionID: String, cardID: UInt32, card: StarlyMetadataViews.Card) {
245 self.editorCapability!.borrow()!.putCollectionCard(collectionID: collectionID, cardID: cardID, card: card)
246 }
247
248 access(all) fun putMetadata(collectionID: String, metadata: CollectionMetadata) {
249 self.editorCapability!.borrow()!.putMetadata(collectionID: collectionID, metadata: metadata)
250 }
251
252 access(all) fun deleteCollectionCard(collectionID: String, cardID: UInt32) {
253 self.editorCapability!.borrow()!.deleteCollectionCard(collectionID: collectionID, cardID: cardID)
254 }
255
256 access(all) fun deleteMetadata(collectionID: String) {
257 self.editorCapability!.borrow()!.deleteMetadata(collectionID: collectionID)
258 }
259
260 init() {
261 self.editorCapability = nil
262 }
263 }
264
265 access(all) fun createEditorProxy(): @EditorProxy {
266 return <- create EditorProxy()
267 }
268
269 access(all) resource Admin {
270 access(all) fun createNewEditor(): @Editor {
271 return <- create Editor()
272 }
273 }
274
275 init() {
276 self.metadata = {}
277
278 self.AdminStoragePath = /storage/starlyMetadataAdmin
279 self.EditorStoragePath = /storage/starlyMetadataEditor
280 self.EditorProxyPublicPath = /public/starlyMetadataEditorProxy
281 self.EditorProxyStoragePath = /storage/starlyMetadataEditorProxy
282
283 let admin <- create Admin()
284 let editor <- admin.createNewEditor()
285 self.account.storage.save(<-admin, to: self.AdminStoragePath)
286 self.account.storage.save(<-editor, to: self.EditorStoragePath)
287 }
288}
289