Smart Contract

StarlyMetadata

A.5b82f21c0edf76e3.StarlyMetadata

Deployed

20h ago
Feb 28, 2026, 02:30:51 AM UTC

Dependents

0 imports
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