Smart Contract
PartyFavorz
A.123cb666996b8432.PartyFavorz
1import NonFungibleToken from 0x1d7e57aa55817448
2import FungibleToken from 0xf233dcee88fe0abe
3import MetadataViews from 0x1d7e57aa55817448
4import FindForge from 0x097bafa4e0b48eef
5import FindPack from 0x097bafa4e0b48eef
6import PartyFavorzExtraData from 0x123cb666996b8432
7import ViewResolver from 0x1d7e57aa55817448
8
9access(all) contract PartyFavorz: NonFungibleToken {
10
11 access(all) var totalSupply: UInt64
12
13 access(all) event ContractInitialized()
14 access(all) event Withdraw(id: UInt64, from: Address?)
15 access(all) event Deposit(id: UInt64, to: Address?)
16 access(all) event Minted(id:UInt64, serial: UInt64, season: UInt64, name: String )
17
18 access(all) let CollectionStoragePath: StoragePath
19 access(all) let CollectionPublicPath: PublicPath
20 access(all) let MinterStoragePath: StoragePath
21
22 access(all) let royalties: [MetadataViews.Royalty]
23
24 access(all) struct Info {
25 access(all) let name: String
26 access(all) let description: String
27 access(all) let thumbnailHash: String
28 access(all) let edition: UInt64
29 access(all) let maxEdition: UInt64
30 access(all) let fullsizeHash: String
31 access(all) let artist: String
32
33 init(name: String, description: String, thumbnailHash: String, edition:UInt64, maxEdition:UInt64, fullsizeHash: String, artist: String) {
34 self.name=name
35 self.description=description
36 self.thumbnailHash=thumbnailHash
37 self.edition=edition
38 self.maxEdition=maxEdition
39 self.fullsizeHash=fullsizeHash
40 self.artist=artist
41 }
42 }
43
44 access(all) resource NFT: NonFungibleToken.NFT, ViewResolver.Resolver {
45 access(all) let id: UInt64
46 access(all) let info: Info
47
48 init(
49 info: Info,
50 season: UInt64,
51 royalties: [MetadataViews.Royalty],
52 squareImage: String,
53 bannerImage: String
54 ) {
55 self.id = self.uuid
56 self.info=info
57
58 PartyFavorzExtraData.setData(id: self.id, field: "season", value: season)
59 PartyFavorzExtraData.setData(id: self.id, field: "royalties", value: royalties)
60 PartyFavorzExtraData.setData(id: self.id, field: "nftCollectionDisplay", value: {"squareImage" : squareImage, "bannerImage" : bannerImage})
61 }
62
63 access(all) view fun getID(): UInt64 {
64 return self.id
65 }
66
67 access(all) view fun getViews(): [Type] {
68 return [
69 Type<MetadataViews.Display>(),
70 Type<MetadataViews.Royalties>(),
71 Type<MetadataViews.Editions>(),
72 Type<MetadataViews.Traits>(),
73 Type<MetadataViews.ExternalURL>(),
74 Type<MetadataViews.NFTCollectionData>(),
75 Type<MetadataViews.NFTCollectionDisplay>(),
76 Type<MetadataViews.Medias>(),
77 Type<FindPack.PackRevealData>()
78 ]
79 }
80
81 access(all) fun resolveView(_ view: Type): AnyStruct? {
82 let imageFile = MetadataViews.IPFSFile( cid: self.info.thumbnailHash, path: nil)
83
84 switch view {
85
86 case Type<FindPack.PackRevealData>():
87 let data : {String : String} = {
88 "nftImage" : imageFile.uri() ,
89 "nftName" : self.info.name,
90 "packType" : "PartyFavorz"
91 }
92 return FindPack.PackRevealData(data)
93
94 case Type<MetadataViews.Display>():
95 return MetadataViews.Display(
96 name: self.info.name,
97 description: self.info.description,
98 thumbnail: MetadataViews.IPFSFile(
99 cid: self.info.thumbnailHash, path: nil
100 )
101 )
102 case Type<MetadataViews.Editions>():
103 let seasonData = PartyFavorzExtraData.getData(id: self.id, field: "season")
104 var season = 1 as UInt64
105 if seasonData != nil {
106 season = seasonData! as! UInt64
107 }
108 let editionInfo = MetadataViews.Edition(name: "season ".concat(season.toString()), number: self.info.edition, max: self.info.maxEdition)
109 let editionList: [MetadataViews.Edition] = [editionInfo]
110 return MetadataViews.Editions(
111 editionList
112 )
113 case Type<MetadataViews.Royalties>():
114 let royaltiesData = PartyFavorzExtraData.getData(id: self.id, field: "royalties")
115 if royaltiesData != nil {
116 let r = royaltiesData! as! [MetadataViews.Royalty]
117 return MetadataViews.Royalties(r)
118 }
119 return MetadataViews.Royalties(PartyFavorz.royalties)
120
121 case Type<MetadataViews.ExternalURL>():
122 if self.owner != nil {
123 return MetadataViews.ExternalURL("https://find.xyz/".concat(self.owner!.address.toString()).concat("/collection/partyfavorz/").concat(self.id.toString()))
124 }
125 return MetadataViews.ExternalURL("https://find.xyz/")
126
127 case Type<MetadataViews.NFTCollectionData>():
128 return PartyFavorz.resolveContractView(resourceType: Type<@PartyFavorz.NFT>(), viewType: Type<MetadataViews.NFTCollectionData>())
129 case Type<MetadataViews.NFTCollectionDisplay>():
130 var square = MetadataViews.Media(
131 file: MetadataViews.IPFSFile(
132 cid: "QmNkJGEzNYzXsKFqCMweFZBZ9cMQsfMUzV2ZDh2Nn8a1Xc",
133 path: nil
134 ),
135 mediaType: "image/png"
136 )
137
138 var banner = MetadataViews.Media(
139 file: MetadataViews.IPFSFile(
140 cid: "QmVuMpDyJXHMCK9LnFboemWfPYabcwPNEmXgQMWbtxtGWD",
141 path: nil
142 ),
143 mediaType: "image/png"
144 )
145
146 let nftCollectionDisplayData = PartyFavorzExtraData.getData(id: self.id, field: "nftCollectionDisplay")
147 if nftCollectionDisplayData != nil {
148 let nftCollectionDisplay = nftCollectionDisplayData! as! {String : String}
149
150 square = MetadataViews.Media(
151 file: MetadataViews.IPFSFile(
152 cid: nftCollectionDisplay["squareImage"]!,
153 path: nil
154 ),
155 mediaType: "image/png"
156 )
157
158 banner = MetadataViews.Media(
159 file: MetadataViews.IPFSFile(
160 cid: nftCollectionDisplay["bannerImage"]!,
161 path: nil
162 ),
163 mediaType: "image/png"
164 )
165 }
166
167 return MetadataViews.NFTCollectionDisplay(
168 name: "PartyFavorz",
169 description: "By owning a Party Favorz NFT, you are granted access to the VIP sections of our virtual parties which include, but are not limited to major giveaways, 1 on 1s with artists/project leaders, and some IRL utility that involves partying, down the line. By owning Party Favorz, you are supporting the idea of community coming together for a few goals that include having fun, being positive, learning, and most importantly SUPPORTING ARTISTS.",
170 externalURL: MetadataViews.ExternalURL("https://find.xyz/partyfavorz"),
171 squareImage: square,
172 bannerImage: banner,
173 socials: {
174 "twitter": MetadataViews.ExternalURL("https://twitter.com/FlowPartyFavorz"),
175 "discord" : MetadataViews.ExternalURL("https://discord.gg/bM76F34EnN")
176 }
177 )
178 case Type<MetadataViews.Traits>() :
179 let seasonData = PartyFavorzExtraData.getData(id: self.id, field: "season")
180 var season = 1 as UInt64
181 if seasonData != nil {
182 season = seasonData! as! UInt64
183 }
184 return MetadataViews.Traits([
185 MetadataViews.Trait(name: "Artist", value: self.info.artist, displayType: "String", rarity: nil) ,
186 MetadataViews.Trait(name: "Season", value: season, displayType: "Numeric", rarity: nil)
187 ])
188
189 case Type<MetadataViews.Medias>() :
190 let seasonData = PartyFavorzExtraData.getData(id: self.id, field: "season")
191 var season = 1 as UInt64
192 if seasonData != nil {
193 season = seasonData! as! UInt64
194 }
195
196 var thumbnailMediaType = "image/png"
197 var fullImageMediaType = "image/png"
198
199 switch season {
200 case 2:
201 fullImageMediaType = "image/gif"
202
203 }
204
205 return MetadataViews.Medias([
206 MetadataViews.Media(file: MetadataViews.IPFSFile(cid: self.info.thumbnailHash, path: nil), mediaType: thumbnailMediaType),
207 MetadataViews.Media(file: MetadataViews.IPFSFile(cid: self.info.fullsizeHash, path: nil), mediaType: fullImageMediaType)
208 ])
209 }
210 return nil
211 }
212
213 access(all) fun createEmptyCollection(): @{NonFungibleToken.Collection} {
214 return <-PartyFavorz.createEmptyCollection(nftType:Type<@PartyFavorz.NFT>())
215 }
216 }
217
218 access(all) view fun getContractViews(resourceType: Type?): [Type] {
219 return [
220 Type<MetadataViews.NFTCollectionData>(),
221 Type<MetadataViews.NFTCollectionDisplay>()
222 ]
223 }
224
225 access(all) fun resolveContractView(resourceType: Type?, viewType: Type): AnyStruct? {
226 switch viewType {
227 case Type<MetadataViews.NFTCollectionData>():
228 let collectionRef = self.account.storage.borrow<&PartyFavorz.Collection>(
229 from: PartyFavorz.CollectionStoragePath
230 ) ?? panic("Could not borrow a reference to the stored collection")
231 let collectionData = MetadataViews.NFTCollectionData(
232 storagePath: PartyFavorz.CollectionStoragePath,
233 publicPath: PartyFavorz.CollectionPublicPath,
234 publicCollection: Type<&PartyFavorz.Collection>(),
235 publicLinkedType: Type<&PartyFavorz.Collection>(),
236 createEmptyCollectionFunction: (fun(): @{NonFungibleToken.Collection} {
237 return <-PartyFavorz.createEmptyCollection(nftType:Type<@PartyFavorz.NFT>())
238 })
239 )
240 return collectionData
241 }
242 return nil
243 }
244
245 access(all) resource Collection: NonFungibleToken.Collection, ViewResolver.ResolverCollection {
246 // dictionary of NFT conforming tokens
247 // NFT is a resource type with an `UInt64` ID field
248 access(all) var ownedNFTs: @{UInt64: {NonFungibleToken.NFT}}
249
250 init () {
251 self.ownedNFTs <- {}
252 }
253
254 // withdraw removes an NFT from the collection and moves it to the caller
255 access(NonFungibleToken.Withdraw) fun withdraw(withdrawID: UInt64): @{NonFungibleToken.NFT} {
256 let token <- self.ownedNFTs.remove(key: withdrawID) ?? panic("missing NFT")
257
258 emit Withdraw(id: token.id, from: self.owner?.address)
259
260 return <-token
261 }
262
263 // deposit takes a NFT and adds it to the collections dictionary
264 // and adds the ID to the id array
265 access(all) fun deposit(token: @{NonFungibleToken.NFT}) {
266 let token <- token as! @PartyFavorz.NFT
267
268 let id: UInt64 = token.id
269
270 // add the new token to the dictionary which removes the old one
271 let oldToken <- self.ownedNFTs[id] <- token
272
273 emit Deposit(id: id, to: self.owner?.address)
274
275 destroy oldToken
276 }
277
278 // getIDs returns an array of the IDs that are in the collection
279 access(all) view fun getIDs(): [UInt64] {
280 return self.ownedNFTs.keys
281 }
282
283 // borrowNFT gets a reference to an NFT in the collection
284 // so that the caller can read its metadata and call its methods
285 access(all) view fun borrowNFT(_ id: UInt64): &{NonFungibleToken.NFT}? {
286 return (&self.ownedNFTs[id])
287 }
288
289 access(all) view fun borrowViewResolver(id: UInt64): &{ViewResolver.Resolver} {
290 let nft = (&self.ownedNFTs[id] as &{NonFungibleToken.NFT}?)
291 let PartyFavorz = nft as! &PartyFavorz.NFT
292 return PartyFavorz
293 }
294
295 access(all) view fun getLength(): Int {
296 return self.ownedNFTs.keys.length
297 }
298
299 access(all) fun createEmptyCollection(): @{NonFungibleToken.Collection} {
300 return <- create PartyFavorz.Collection()
301 }
302
303 /// getSupportedNFTTypes returns a list of NFT types that this receiver accepts
304 access(all) view fun getSupportedNFTTypes(): {Type: Bool} {
305 let supportedTypes: {Type: Bool} = {}
306 supportedTypes[Type<@PartyFavorz.NFT>()] = true
307 return supportedTypes
308 }
309
310 /// Return the default storage path for the collection
311 access(all) view fun getDefaultStoragePath(): StoragePath? {
312 return PartyFavorz.CollectionStoragePath
313
314 }
315
316 /// Return the default public path for the collection
317 access(all) view fun getDefaultPublicPath(): PublicPath? {
318 return PartyFavorz.CollectionPublicPath
319 }
320
321 /// Returns whether or not the given type is accepted by the collection
322 /// A collection that can accept any type should just return true by default
323 access(all) view fun isSupportedNFTType(type: Type): Bool {
324 if type == Type<@PartyFavorz.NFT>() {
325 return true
326 } else {
327 return false
328 }
329 }
330 }
331
332 // public function that anyone can call to create a new empty collection
333 access(all) fun createEmptyCollection(nftType:Type): @{NonFungibleToken.Collection} {
334 return <- create Collection()
335 }
336
337 access(all) resource Forge: FindForge.Forge {
338 access(FindForge.ForgeOwner) fun mint(platform: FindForge.MinterPlatform, data: AnyStruct, verifier: &FindForge.Verifier) : @{NonFungibleToken.NFT} {
339 let info = data as? {String : AnyStruct} ?? panic("The data passed in is not in form as needed.")
340
341 assert(info.length == 5, message: "Please make sure to pass in `Info, season, royalties, squareImage, bannerImage`")
342
343 // create a new NFT
344 var newNFT <- create NFT(
345 info: info["info"]! as! Info,
346 season: info["season"]! as! UInt64,
347 royalties: info["royalties"]! as! [MetadataViews.Royalty],
348 squareImage: info["squareImage"]! as! String,
349 bannerImage: info["bannerImage"]! as! String
350 )
351
352 PartyFavorz.totalSupply = PartyFavorz.totalSupply + 1
353 emit Minted(id:newNFT.id, serial: PartyFavorz.totalSupply, season: info["season"]! as! UInt64 , name: newNFT.info.name )
354 return <- newNFT
355 }
356
357
358 access(FindForge.ForgeOwner) fun addContractData(platform: FindForge.MinterPlatform, data: AnyStruct, verifier: &FindForge.Verifier) {
359 // not used here
360 panic("Not supported for PartyFavorz Contract")
361 }
362 }
363
364 access(all) fun getForgeType() : Type {
365 return Type<@Forge>()
366 }
367
368 init() {
369 // Initialize the total supply
370 self.totalSupply = 0
371
372 // Set the named paths
373 self.CollectionStoragePath = /storage/PartyFavorzCollection
374 self.CollectionPublicPath = /public/PartyFavorzCollection
375 self.MinterStoragePath = /storage/PartyFavorzMinter
376
377 // TODO: Fix this to run on tests
378 let partyFavorz = self.account.capabilities.get<&{FungibleToken.Receiver}>(/public/flowTokenReceiver)
379 let artist = self.account.capabilities.get<&{FungibleToken.Receiver}>(/public/flowTokenReceiver)
380
381 self.royalties = [
382 MetadataViews.Royalty(receiver: partyFavorz, cut: 0.03, description: "Party Favorz"),
383 MetadataViews.Royalty(receiver: artist, cut: 0.02, description: "Artist")
384 ]
385
386 // Create a Collection resource and save it to storage
387 let collection <- create Collection()
388 self.account.storage.save(<-collection, to: self.CollectionStoragePath)
389 let collectionCap = self.account.capabilities.storage.issue<&{NonFungibleToken.Collection}>(self.CollectionStoragePath)
390 self.account.capabilities.publish(collectionCap, at: self.CollectionPublicPath)
391
392 FindForge.addForgeType(<- create Forge())
393 emit ContractInitialized()
394 }
395}
396
397
398