Smart Contract

Pack

A.de7a5daf9df48c65.Pack

Deployed

2d ago
Feb 25, 2026, 07:34:50 AM UTC

Dependents

55 imports
1import BasicBeasts from 0xde7a5daf9df48c65
2import ViewResolver from 0x1d7e57aa55817448
3import HunterScore from 0xde7a5daf9df48c65
4import NonFungibleToken from 0x1d7e57aa55817448
5import FungibleToken from 0xf233dcee88fe0abe
6import MetadataViews from 0x1d7e57aa55817448
7
8access(all) contract Pack: NonFungibleToken { 
9
10	// -----------------------------------------------------------------------
11	// Entitlements
12	// -----------------------------------------------------------------------
13	access(all) entitlement NFTOwner
14	access(all) entitlement PackManagerOwner
15	access(all) entitlement CollectionOwner
16	access(all) entitlement AdminOwner
17	
18	// -----------------------------------------------------------------------
19	// NonFungibleToken Standard Events
20	// -----------------------------------------------------------------------
21	access(all) event ContractInitialized()
22	access(all) event Withdraw(id: UInt64, from: Address?)
23	access(all) event Deposit(id: UInt64, to: Address?)
24	
25	// -----------------------------------------------------------------------
26	// Pack Events
27	// -----------------------------------------------------------------------
28	access(all) event PackOpened(id: UInt64, packTemplateID: UInt32, beastID: UInt64, beastTemplateID: UInt32, serialNumber: UInt32, sex: String, firstOwner: Address?)
29	access(all) event PackTemplateCreated(packTemplateID: UInt32, name: String)
30	access(all) event PackMinted(id: UInt64, name: String)
31	
32	// -----------------------------------------------------------------------
33	// Named Paths
34	// -----------------------------------------------------------------------
35	access(all) let PackManagerStoragePath: StoragePath
36	access(all) let PackManagerPublicPath: PublicPath
37	access(all) let CollectionStoragePath: StoragePath
38	access(all) let CollectionPublicPath: PublicPath
39	access(all) let AdminStoragePath: StoragePath
40	access(all) let AdminPrivatePath: PrivatePath
41	
42	// -----------------------------------------------------------------------
43	// NonFungibleToken Standard Fields
44	// -----------------------------------------------------------------------
45	access(all) var totalSupply: UInt64
46	
47	// -----------------------------------------------------------------------
48	// Pack Fields
49	// -----------------------------------------------------------------------
50	access(self) var packTemplates:{ UInt32: PackTemplate}
51	access(self) var stockNumbers: [UInt64]
52	access(self) var numberMintedPerPackTemplate:{ UInt32: UInt32}
53	
54	access(all) struct PackTemplate { 
55		access(all) let packTemplateID: UInt32
56		access(all) let name: String
57		access(all) let image: String
58		access(all) let description: String
59		
60		init(packTemplateID: UInt32, name: String, image: String, description: String){ 
61			pre{ 
62				name != "":
63					"Can't create PackTemplate: name can't be blank"
64				image != "":
65					"Can't create PackTemplate: image can't be blank"
66				description != "":
67					"Can't create PackTemplate: description can't be blank"
68			}
69			self.packTemplateID = packTemplateID
70			self.name = name
71			self.image = image
72			self.description = description
73		}
74	}
75	
76	access(all) resource interface Public { 
77		access(all) let id: UInt64
78		access(all) let stockNumber: UInt64
79		access(all) let serialNumber: UInt32
80		access(all) let packTemplate: PackTemplate
81		access(all) var opened: Bool
82		access(all) view fun isOpened(): Bool
83		access(all) view fun containsFungibleTokens(): Bool
84		access(all) view fun containsBeast(): Bool
85		access(all) view fun getNumberOfFungibleTokenVaults(): Int
86		access(all) view fun getNumberOfBeasts(): Int
87	}
88	
89	access(all) resource NFT: NonFungibleToken.NFT, Public, ViewResolver.Resolver { 
90		access(all) let id: UInt64
91		access(all) let stockNumber: UInt64
92		access(all) let serialNumber: UInt32
93		access(all) let packTemplate: PackTemplate
94		access(all) var opened: Bool
95		access(contract) var fungibleTokens: @[{FungibleToken.Vault}]
96		access(contract) var beast: @{UInt64: BasicBeasts.NFT}
97		
98		init(stockNumber: UInt64, packTemplateID: UInt32){ 
99			pre{ 
100				!Pack.stockNumbers.contains(stockNumber):
101					"Can't mint Pack NFT: pack stock number has already been minted"
102				Pack.packTemplates[packTemplateID] != nil:
103					"Can't mint Pack NFT: packTemplate does not exist"
104			}
105			Pack.totalSupply = Pack.totalSupply + 1
106			Pack.stockNumbers.append(stockNumber)
107			Pack.numberMintedPerPackTemplate[packTemplateID] = Pack.numberMintedPerPackTemplate[packTemplateID]! + 1
108			self.serialNumber = Pack.numberMintedPerPackTemplate[packTemplateID]!
109			self.id = stockNumber
110			self.stockNumber = stockNumber
111			self.packTemplate = Pack.packTemplates[packTemplateID]!
112			self.opened = false
113			self.fungibleTokens <- []
114			self.beast <-{} 
115		}
116		
117		access(NFTOwner) fun retrieveAllFungibleTokens(): @[{FungibleToken.Vault}] { 
118			pre { 
119				self.containsFungibleTokens():
120					"Can't retrieve fungible token vaults: Pack does not contain vaults"
121			}
122			var tokens: @[{FungibleToken.Vault}] <- []
123			self.fungibleTokens <-> tokens
124			return <-tokens
125		}
126		
127		access(contract) fun updateIsOpened() { 
128			if self.beast.keys.length == 0 { 
129				self.opened = true
130			}
131		}
132		
133		access(contract) fun insertBeast(beast: @BasicBeasts.NFT) { 
134			pre { 
135				self.beast.keys.length == 0:
136					"Can't insert Beast into Pack: Pack already contain a Beast"
137				!self.isOpened():
138					"Can't insert Beast into Pack: Pack has already been opened"
139			}
140			let id = beast.id
141			self.beast[id] <-! beast
142		}
143		
144		access(contract) fun retrieveBeast(): @BasicBeasts.NFT? { 
145			if self.containsBeast(){ 
146				let keys = self.beast.keys
147				return <-self.beast.remove(key: keys[0])!
148			}
149			return nil
150		}
151		
152		access(contract) fun insertFungible(vault: @{FungibleToken.Vault}) { 
153			self.fungibleTokens.append(<-vault)
154		}
155		
156		access(all) view fun isOpened(): Bool{ 
157			return self.opened
158		}
159		
160		access(all) view fun containsFungibleTokens(): Bool{ 
161			return self.fungibleTokens.length > 0
162		}
163		
164		access(all) view fun containsBeast(): Bool { 
165			return self.beast.keys.length > 0
166		}
167		
168		access(all) view fun getNumberOfFungibleTokenVaults(): Int { 
169			return self.fungibleTokens.length
170		}
171		
172		access(all) view fun getNumberOfBeasts(): Int { 
173			return self.beast.keys.length
174		}
175		
176		access(all) view fun getViews(): [Type] { 
177			return [Type<MetadataViews.Display>()]
178		}
179		
180		access(all) view fun resolveView(_ view: Type): AnyStruct? { 
181			switch view{ 
182				case Type<MetadataViews.Display>():
183					return MetadataViews.Display(name: self.packTemplate.name, description: self.packTemplate.description, thumbnail: MetadataViews.IPFSFile(cid: self.packTemplate.image, path: nil))
184			}
185			return nil
186		}
187		
188		access(all) fun createEmptyCollection(): @{NonFungibleToken.Collection}{ 
189			return <-create Collection()
190		}
191	}
192	
193	access(all) resource interface PublicPackManager { 
194		access(all) let id: UInt64
195	}
196	
197	// A Pack Manager resource allows the holder to retrieve a beast from a pack and destroy the pack NFT after it has been unpacked.
198	access(all) resource PackManager: PublicPackManager { 
199		access(all) let id: UInt64
200		
201		init(){ 
202			self.id = self.uuid
203		}
204		
205		access(PackManagerOwner) fun retrieveBeast(pack: @NFT): @BasicBeasts.Collection { 
206			pre{ 
207				pack.containsBeast():
208					"Can't retrieve beast: Pack does not contain a beast"
209				self.owner != nil:
210					"Can't retrieve beast: self.owner is nil"
211			}
212			let keys = pack.beast.keys
213			let beastCollection <- BasicBeasts.createEmptyCollection(nftType: Type<@BasicBeasts.Collection>()) as! @BasicBeasts.Collection
214			let beastRef: &BasicBeasts.NFT = (&pack.beast[keys[0]] as &BasicBeasts.NFT?)!
215			let beast <- pack.retrieveBeast()!
216			beast.setFirstOwner(firstOwner: (self.owner!).address)
217			beastCollection.deposit(token: <-beast)
218			let newBeastCollection <- HunterScore.increaseHunterScore(wallet: (self.owner!).address, beasts: <-beastCollection)
219			pack.updateIsOpened()
220			if pack.isOpened(){ 
221				emit PackOpened(id: pack.id, packTemplateID: pack.packTemplate.packTemplateID, beastID: beastRef.id, beastTemplateID: beastRef.getBeastTemplate().beastTemplateID, serialNumber: beastRef.serialNumber, sex: beastRef.sex, firstOwner: beastRef.getFirstOwner())
222			}
223			destroy pack
224			return <-newBeastCollection
225		}
226	}
227	
228	// -----------------------------------------------------------------------
229	// Admin Resource Functions
230	//
231	// Admin is a special authorization resource that 
232	// allows the owner to perform important NFT functions
233	// -----------------------------------------------------------------------
234	access(all) resource Admin { 
235		access(AdminOwner) fun createPackTemplate(packTemplateID: UInt32, name: String, image: String, description: String): UInt32 { 
236			pre{ 
237				Pack.packTemplates[packTemplateID] == nil:
238					"Can't create PackTemplate: Pack Template ID already exist"
239			}
240			var newPackTemplate = PackTemplate(packTemplateID: packTemplateID, name: name, image: image, description: description)
241			Pack.packTemplates[packTemplateID] = newPackTemplate
242			Pack.numberMintedPerPackTemplate[packTemplateID] = 0
243			emit PackTemplateCreated(packTemplateID: newPackTemplate.packTemplateID, name: newPackTemplate.name)
244			return newPackTemplate.packTemplateID
245		}
246		
247		access(AdminOwner) fun mintPack(stockNumber: UInt64, packTemplateID: UInt32): @Pack.NFT { 
248			let newPack: @Pack.NFT <- Pack.mintPack(stockNumber: stockNumber, packTemplateID: packTemplateID)
249			return <-newPack
250		}
251		
252		access(AdminOwner) fun insertBeast(pack: @Pack.NFT, beast: @BasicBeasts.NFT): @Pack.NFT { 
253			pre{ 
254				pack.beast.keys.length == 0:
255					"Can't insert Beast into Pack: Pack already contain a Beast"
256				!pack.isOpened():
257					"Can't insert Beast into Pack: Pack has already been opened"
258			}
259			let id = beast.id
260			pack.insertBeast(beast: <-beast)
261			return <-pack
262		}
263		
264		access(AdminOwner) fun insertFungible(pack: @Pack.NFT, vault: @{FungibleToken.Vault}): @Pack.NFT { 
265			pack.insertFungible(vault: <-vault)
266			return <-pack
267		}
268		
269		access(AdminOwner) fun createNewAdmin(): @Admin { 
270			return <-create Admin()
271		}
272	}
273	
274	access(all) resource interface PackCollectionPublic{ 
275		access(all) fun deposit(token: @{NonFungibleToken.NFT}): Void
276		access(all) view fun getIDs(): [UInt64]
277		access(all) view fun borrowNFT(_ id: UInt64): &{NonFungibleToken.NFT}?
278		access(all) view fun borrowPack(id: UInt64): &Pack.NFT? { 
279			post{ 
280				result == nil || result?.id == id:
281					"Cannot borrow Pack reference: The ID of the returned reference is incorrect"
282			}
283		}
284	}
285	
286	access(all) resource Collection: PackCollectionPublic, NonFungibleToken.Provider, NonFungibleToken.Receiver, NonFungibleToken.Collection, NonFungibleToken.CollectionPublic, ViewResolver.ResolverCollection { 
287		access(all) var ownedNFTs: @{UInt64:{ NonFungibleToken.NFT}}
288		
289		init(){ 
290			self.ownedNFTs <-{} 
291		}
292		
293		access(NonFungibleToken.Withdraw) fun withdraw(withdrawID: UInt64): @{NonFungibleToken.NFT}{ 
294			let token <- self.ownedNFTs.remove(key: withdrawID) ?? panic("Cannot withdraw: The Pack does not exist in the Collection")
295			emit Withdraw(id: token.id, from: self.owner?.address)
296			return <-token
297		}
298		
299		access(all) fun deposit(token: @{NonFungibleToken.NFT}): Void{ 
300			let token <- token as! @Pack.NFT
301			let id = token.id
302			let oldToken <- self.ownedNFTs[id] <- token
303			if self.owner?.address != nil{ 
304				emit Deposit(id: id, to: self.owner?.address)
305			}
306			destroy oldToken
307		}
308		
309		access(all) view fun getIDs(): [UInt64]{ 
310			return self.ownedNFTs.keys
311		}
312		
313		access(all) view fun borrowNFT(_ id: UInt64): &{NonFungibleToken.NFT}?{ 
314			return (&self.ownedNFTs[id] as &{NonFungibleToken.NFT}?)!
315		}
316		
317		access(all) view fun borrowPack(id: UInt64): &Pack.NFT?{ 
318			let ref = &self.ownedNFTs[id] as &{NonFungibleToken.NFT}?
319			return ref as! &Pack.NFT?
320		}
321		
322		access(CollectionOwner) fun borrowEntirePack(id: UInt64): &Pack.NFT?{ 
323			let ref = &self.ownedNFTs[id] as &{NonFungibleToken.NFT}?
324			return ref as! &Pack.NFT?
325		}
326		
327		access(all) view fun borrowViewResolver(id: UInt64): &{ViewResolver.Resolver}?{ 
328			let nft = (&self.ownedNFTs[id] as &{NonFungibleToken.NFT}?)!
329			let packNFT = nft as! &Pack.NFT
330			return packNFT
331		}
332		
333		access(all) view fun getSupportedNFTTypes():{ Type: Bool} { 
334			return {
335				Type<@Pack.NFT>(): true
336			}
337		}
338		
339		access(all) view fun isSupportedNFTType(type: Type): Bool { 
340			return type == Type<@Pack.NFT>()
341		}
342		
343		access(all) fun createEmptyCollection(): @{NonFungibleToken.Collection}{ 
344			return <-create Collection()
345		}
346	}
347	
348	// -----------------------------------------------------------------------
349	// Access(Account) Functions
350	// -----------------------------------------------------------------------
351	access(account) fun mintPack(stockNumber: UInt64, packTemplateID: UInt32): @Pack.NFT { 
352		let newPack: @Pack.NFT <- create NFT(stockNumber: stockNumber, packTemplateID: packTemplateID)
353		emit PackMinted(id: newPack.id, name: newPack.packTemplate.name)
354		return <-newPack
355	}
356	
357	// -----------------------------------------------------------------------
358	// Public Functions
359	// -----------------------------------------------------------------------
360	access(all) fun createNewPackManager(): @PackManager { 
361		return <-create PackManager()
362	}
363	
364	access(all) view fun getAllPackTemplates():{ UInt32: PackTemplate} { 
365		return self.packTemplates
366	}
367	
368	access(all) view fun getPackTemplate(packTemplateID: UInt32): PackTemplate? { 
369		return self.packTemplates[packTemplateID]
370	}
371	
372	access(all) view fun getAllstockNumbers(): [UInt64] { 
373		return self.stockNumbers
374	}
375	
376	access(all) view fun isMinted(stockNumber: UInt64): Bool { 
377		return self.stockNumbers.contains(stockNumber)
378	}
379	
380	access(all) view fun getAllNumberMintedPerPackTemplate():{ UInt32: UInt32} { 
381		return self.numberMintedPerPackTemplate
382	}
383	
384	access(all) view fun getNumberMintedPerPackTemplate(packTemplateID: UInt32): UInt32? { 
385		return self.numberMintedPerPackTemplate[packTemplateID]
386	}
387	
388	// -----------------------------------------------------------------------
389	// NonFungibleToken Standard Functions
390	// -----------------------------------------------------------------------
391	access(all) fun createEmptyCollection(nftType: Type): @{NonFungibleToken.Collection}{ 
392		return <-create self.Collection()
393	}
394
395	// -----------------------------------------------------------------------
396	// MetadataViews - Purposely Empty
397	// -----------------------------------------------------------------------
398	access(all) fun resolveContractView(resourceType: Type?, viewType: Type): AnyStruct? {
399		return nil
400	}
401
402	access(all) view fun getContractViews(resourceType: Type?): [Type] {
403		return []
404	}
405	
406	init(){ 
407		// Set named paths
408		self.PackManagerStoragePath = /storage/BasicBeastsPackManager
409		self.PackManagerPublicPath = /public/BasicBeastsPackManager
410		self.CollectionStoragePath = /storage/BasicBeastsPackCollection
411		self.CollectionPublicPath = /public/BasicBeastsPackCollection
412		self.AdminStoragePath = /storage/BasicBeastsPackAdmin
413		self.AdminPrivatePath = /private/BasicBeastsPackAdminUpgrade
414		
415		// Initialize the fields
416		self.totalSupply = 0
417		self.packTemplates ={} 
418		self.stockNumbers = []
419		self.numberMintedPerPackTemplate ={} 
420		
421		// Put Admin in storage
422		self.account.storage.save(<-create Admin(), to: self.AdminStoragePath)
423		emit ContractInitialized()
424	}
425}
426// Thank you swt and raven for reviewing this pack contract with me. Jacob sucks...
427
428