Smart Contract
PuffPalz
A.a3eb9784ae7dc9c8.PuffPalz
1//import "NonFungibleToken"
2//import "ViewResolver"
3//import "MetadataViews"
4
5
6// Mainnet
7import NonFungibleToken from 0x1d7e57aa55817448
8import MetadataViews from 0x1d7e57aa55817448
9import ViewResolver from 0x1d7e57aa55817448
10
11
12//Testnet
13//import NonFungibleToken from 0x631e88ae7f1d7c20
14//import MetadataViews from 0x631e88ae7f1d7c20
15//import FlowToken from 0x7e60df042a9c0868
16//import FungibleToken from 0x9a0766d93b6608b7
17
18
19
20
21
22
23access(all) contract PuffPalz: NonFungibleToken {
24
25
26 //Define Events
27 access(all) event ContractInitialized()
28 access(all) event Withdraw(id: UInt64, from: Address?)
29 access(all) event Deposit(id: UInt64, to: Address?)
30 access(all) event ExclusiveMinted(id: UInt64, name: String, description: String, image: String, traits: {String:String})
31
32
33 //Define Paths
34 access(all) let CollectionStoragePath: StoragePath
35 access(all) let CollectionPublicPath: PublicPath
36 access(all) let CollectionPrivatePath: PrivatePath
37 access(all) let AdminStoragePath: StoragePath
38
39
40 //Difine Total Supply
41 access(all) var totalSupply: UInt64
42
43
44 access(all) struct puffPalzMetadata {
45 access(all) let id: UInt64
46 access(all) let name: String
47 access(all) let description: String
48 access(all) let image: String
49 access(all) let traits: {String:String}
50
51
52 init(_id: UInt64, _name: String, _description: String, _image: String, _traits:{String:String}) {
53 self.id = _id
54 self.name = _name
55 self.description = _description
56 self.image = _image
57 self.traits = _traits
58 }
59 }
60
61
62 access(all) resource NFT: NonFungibleToken.NFT {
63
64
65 access(all) let id: UInt64
66 access(all) let name: String
67 access(all) let description: String
68 access(all) var image: String
69 access(all) let traits: {String: String}
70
71
72 init( _id: UInt64, _name: String, _description: String, _image: String, _traits: {String:String}) {
73
74 self.id = _id
75 self.name = _name
76 self.description = _description
77 self.image = _image
78 self.traits = _traits
79 }
80
81
82 access(all) fun createEmptyCollection(): @{NonFungibleToken.Collection} {
83 return <- PuffPalz.createEmptyCollection(nftType: Type<@PuffPalz.NFT>())
84 }
85
86
87
88
89 access(all) fun revealThumbnail() {
90 let urlBase = self.image.slice(from: 0, upTo: 47)
91 let newImage = urlBase.concat(self.id.toString()).concat(".png")
92 self.image = newImage
93 }
94
95
96 access(all) view fun getViews(): [Type] {
97 return [
98 Type<MetadataViews.Display>(),
99 Type<MetadataViews.ExternalURL>(),
100 Type<MetadataViews.NFTCollectionData>(),
101 Type<MetadataViews.NFTCollectionDisplay>(),
102 Type<PuffPalz.puffPalzMetadata>(),
103 Type<MetadataViews.Royalties>(),
104 Type<MetadataViews.Traits>()
105 ]
106 }
107
108
109 access(all) fun resolveView(_ viewType: Type): AnyStruct? {
110 switch viewType {
111
112
113 case Type<MetadataViews.Display>():
114 return MetadataViews.Display(
115 name: self.name,
116 description: self.description,
117 thumbnail: MetadataViews.IPFSFile(
118 cid: self.image,
119 path: nil
120 )
121 )
122
123
124 case Type<MetadataViews.ExternalURL>():
125 return MetadataViews.ExternalURL("https://puffpalz.io/")
126
127
128 case Type<MetadataViews.NFTCollectionData>():
129 return PuffPalz.resolveContractView(resourceType: nil, viewType: Type<MetadataViews.NFTCollectionData>())
130 case Type<MetadataViews.NFTCollectionDisplay>():
131 return PuffPalz.resolveContractView(resourceType: nil, viewType: Type<MetadataViews.NFTCollectionDisplay>())
132
133
134 case Type<PuffPalz.puffPalzMetadata>():
135 return PuffPalz.puffPalzMetadata(
136 _id: self.id,
137 _name: self.name,
138 _description: self.description,
139 _image: self.image,
140 _traits: self.traits
141 )
142
143
144
145 case Type<MetadataViews.Royalties>():
146 return MetadataViews.Royalties([])
147 /*return MetadataViews.Royalties([
148 MetadataViews.Royalty(
149 recipientOne: getAccount(0x818c4380b6a072f1).getCapability<&FlowToken.Vault>(/public/flowTokenReceiver),
150 cut: 0.01,
151 description: "1% Royalty for artist"
152 ),
153 MetadataViews.Royalty(
154 recipientTwo: getAccount(0x57599414d2173726).getCapability<&FlowToken.Vault>(/public/flowTokenReceiver),
155 cut: 0.01,
156 description: "1% Royalty for dev"
157 ),
158 MetadataViews.Royalty(
159 recipientThree: getAccount(0xac391223d88c98e4).getCapability<&FlowToken.Vault>(/public/flowTokenReceiver),
160 cut: 0.03,
161 description: "3% Royalty for treasury"
162 )
163 ]) */
164 case Type<MetadataViews.Traits>():
165 let traits: [MetadataViews.Trait] = []
166 for trait in self.traits.keys {
167 traits.append(MetadataViews.Trait(
168 name: trait,
169 value: self.traits[trait]!,
170 displayType: nil,
171 rarity: nil
172 ))
173 }
174 return MetadataViews.Traits(traits)
175
176 }
177 return nil
178 }
179
180
181
182 }
183
184 access(all) resource interface CollectionPublic : NonFungibleToken.CollectionPublic {
185 access(all) fun deposit(token: @{NonFungibleToken.NFT})
186 access(all) fun borrowPuffPalz(id: UInt64): &PuffPalz.NFT? {
187 // If the result isn't nil, the id of the returned reference
188 // should be the same as the argument to the function
189 post {
190 (result == nil) || (result?.id == id):
191 "Cannot borrow Moment reference: The ID of the returned reference is incorrect"
192 }
193 }
194 }
195
196
197 access(all) resource Collection: CollectionPublic, NonFungibleToken.Collection {
198 // dictionary of NFT conforming tokens
199 // NFT is a resource type with an 'UInt64' ID field
200 access(all) var ownedNFTs: @{UInt64: {NonFungibleToken.NFT}}
201
202
203 access(all) view fun getSupportedNFTTypes(): {Type: Bool} {
204 let supportedType: {Type: Bool} = {}
205 supportedType[Type<@PuffPalz.NFT>()] = true
206 return supportedType
207 }
208
209
210 access(all) view fun isSupportedNFTType(type: Type): Bool {
211 if type == Type<@PuffPalz.NFT>() {
212 return true
213 }
214 return false
215
216 }
217
218
219 // withdraw removes an NFT from the collection and moves it to the caller
220 access(NonFungibleToken.Withdraw) fun withdraw(withdrawID: UInt64): @{NonFungibleToken.NFT} {
221 let token <- self.ownedNFTs.remove(key: withdrawID) ?? panic("missing NFT")
222
223
224 return <-token
225 }
226
227
228 // deposit takes a NFT and adds it to the collections dictionary
229 // and adds the ID to the id array
230 access(all) fun deposit(token: @{NonFungibleToken.NFT}) {
231 let token <- token as! @PuffPalz.NFT
232
233
234 let id: UInt64 = token.id
235
236
237 let oldToken <- self.ownedNFTs[id] <- token
238
239 destroy oldToken
240
241 }
242
243
244 // getIDs returns an array of the IDs that are in the collection
245 access(all) view fun getIDs(): [UInt64] {
246 return self.ownedNFTs.keys
247 }
248
249
250 access(all) view fun getLength(): Int {
251 return self.ownedNFTs.keys.length
252 }
253
254
255 access(all) view fun borrowViewResolver(id: UInt64): &{ViewResolver.Resolver}? {
256 if let nft = &self.ownedNFTs[id] as &{NonFungibleToken.NFT}? {
257 return nft as &{ViewResolver.Resolver}
258 }
259 return nil
260 }
261
262
263
264
265 // borrowNFT gets a reference to an NFT in the collection
266 // so that the caller can read its metadata and call its methods
267 access(all) view fun borrowNFT(_ id: UInt64): &{NonFungibleToken.NFT}? {
268 return (&self.ownedNFTs[id] as &{NonFungibleToken.NFT}?)!
269 }
270
271
272 access(all) fun borrowPuffPalz(id: UInt64): &PuffPalz.NFT? {
273 if let nft = &self.ownedNFTs[id] as &{NonFungibleToken.NFT}? {
274 return nft as! &NFT
275 }
276 return nil
277 }
278
279
280 init () {
281 self.ownedNFTs <- {}
282 }
283
284
285 access(all) fun createEmptyCollection(): @{NonFungibleToken.Collection} {
286 return <- create Collection()
287 }
288
289
290
291
292 }
293
294 access(all) view fun getContractViews(resourceType: Type?): [Type] {
295 return [Type<MetadataViews.NFTCollectionData>(), Type<MetadataViews.NFTCollectionDisplay>(), Type<MetadataViews.Royalties>()]
296 }
297
298 /// Resolve this contract's metadata views
299 ///
300 access(all) view fun resolveContractView(resourceType: Type?, viewType: Type): AnyStruct? {
301 post {
302 result == nil || result!.getType() == viewType: "The returned view must be of the given type or nil"
303 }
304 switch viewType {
305 case Type<MetadataViews.NFTCollectionData>():
306 return MetadataViews.NFTCollectionData(
307 storagePath: /storage/PuffPalzCollection,
308 publicPath: /public/PuffPalzCollection,
309 publicCollection: Type<&PuffPalz.Collection>(),
310 publicLinkedType: Type<&PuffPalz.Collection>(),
311 createEmptyCollectionFunction: (fun (): @{NonFungibleToken.Collection} {
312 return <-PuffPalz.createEmptyCollection(nftType: Type<@PuffPalz.NFT>())
313 })
314 )
315 case Type<MetadataViews.NFTCollectionDisplay>():
316 let squareMedia = MetadataViews.Media(
317 file: MetadataViews.HTTPFile(
318 url: "https://puffpalz.io/static/media/logo_trans.23a0132ea8d91f699ce0.webp"
319 ),
320 mediaType: "image"
321 )
322 let bannerMedia = MetadataViews.Media(
323 file: MetadataViews.HTTPFile(
324 url: "https://puffpalz.io/static/media/logo_trans.23a0132ea8d91f699ce0.webp"
325 ),
326 mediaType: "image"
327 )
328 return MetadataViews.NFTCollectionDisplay(
329 name: "NBA-Top-Shot",
330 description: "Welcome to Puff Palz! An NFT collection of 42 animals that enjoy the devil's lettuce Are you a Smoker, Grower, Pusher, or the Top of the Food Chain?!",
331 externalURL: MetadataViews.ExternalURL("https://puffpalz.io"),
332 squareImage: squareMedia,
333 bannerImage: bannerMedia,
334 socials: {
335 "twitter": MetadataViews.ExternalURL("https://x.com/PuffPalz"),
336 "discord": MetadataViews.ExternalURL("https://discord.gg/nDxrtnxN")
337 }
338 )
339
340 }
341 return nil
342 }
343
344
345 access(all) fun createEmptyCollection(nftType: Type): @{NonFungibleToken.Collection} {
346 return <- create Collection()
347 }
348
349
350 access(all) resource Admin {
351 access(all) fun mintNFT(
352 recipient: &{NonFungibleToken.CollectionPublic},
353 name: String,
354 description: String,
355 image: String,
356 traits: {String:String}
357 ) {
358 emit ExclusiveMinted(id: PuffPalz.totalSupply, name: name, description: description, image: image, traits: traits)
359 PuffPalz.totalSupply = PuffPalz.totalSupply + (1 as UInt64)
360
361
362 recipient.deposit(token: <- create PuffPalz.NFT(
363 _id: PuffPalz.totalSupply,
364 _name: name,
365 _description: description,
366 _image: image,
367 _traits: traits
368 )
369 )
370 }
371 }
372
373
374 init() {
375
376 self.CollectionStoragePath = /storage/PuffPalzCollection
377 self.CollectionPublicPath = /public/PuffPalzCollection
378 self.CollectionPrivatePath = /private/PuffPalzCollection
379 self.AdminStoragePath = /storage/PuffPalzMinter
380
381
382 self.totalSupply = 0
383
384
385 let minter <- create Admin()
386 self.account.storage.save(<-minter, to: self.AdminStoragePath)
387
388
389 let collection <- create Collection()
390 self.account.storage.save(<- collection, to: self.CollectionStoragePath)
391
392
393 let collectionCap = self.account.capabilities.storage.issue<&PuffPalz.Collection>(self.CollectionStoragePath)
394 self.account.capabilities.publish(collectionCap, at: self.CollectionPublicPath)
395
396 emit ContractInitialized()
397 }
398}
399