Smart Contract

PuffPalz

A.a3eb9784ae7dc9c8.PuffPalz

Deployed

2d ago
Feb 25, 2026, 01:04:22 AM UTC

Dependents

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