Smart Contract

BasicBeasts

A.de7a5daf9df48c65.BasicBeasts

Deployed

2d ago
Feb 26, 2026, 11:00:52 AM UTC

Dependents

0 imports
1import NonFungibleToken from 0x1d7e57aa55817448
2import ViewResolver from 0x1d7e57aa55817448
3import MetadataViews from 0x1d7e57aa55817448
4import FlowToken from 0x1654653399040a61
5
6access(all) contract BasicBeasts: NonFungibleToken { 
7
8	// -----------------------------------------------------------------------
9	// Entitlements
10	// -----------------------------------------------------------------------
11	access(all) entitlement NFTOwner
12	access(all) entitlement AdminOwner
13	
14	// -----------------------------------------------------------------------
15	// NonFungibleToken Standard Events
16	// -----------------------------------------------------------------------
17	access(all) event ContractInitialized()
18	access(all) event Withdraw(id: UInt64, from: Address?)
19	access(all) event Deposit(id: UInt64, to: Address?)
20	
21	// -----------------------------------------------------------------------
22	// BasicBeasts Events
23	// -----------------------------------------------------------------------
24	access(all) event BeastMinted(id: UInt64, address: Address?, beastTemplateID: UInt32, serialNumber: UInt32, sex: String, matron: BeastNftStruct?, sire: BeastNftStruct?)
25	access(all) event BeastNewNicknameSet(id: UInt64, nickname: String)
26	access(all) event BeastFirstOwnerSet(id: UInt64, firstOwner: Address)
27	access(all) event BeastDestroyed(id: UInt64, serialNumber: UInt32, beastTemplateID: UInt32)
28	access(all) event BeastTemplateCreated(beastTemplateID: UInt32, name: String, skin: String)
29	access(all) event NewGenerationStarted(newCurrentGeneration: UInt32)
30	access(all) event BeastRetired(beastTemplateID: UInt32, numberMintedPerBeastTemplate: UInt32)
31	
32	// -----------------------------------------------------------------------
33	// Named Paths
34	// -----------------------------------------------------------------------
35	access(all) let CollectionStoragePath: StoragePath
36	access(all) let CollectionPublicPath: PublicPath
37	access(all) let CollectionPrivatePath: PrivatePath
38	access(all) let AdminStoragePath: StoragePath
39	access(all) let AdminPrivatePath: PrivatePath
40	
41	// -----------------------------------------------------------------------
42	// NonFungibleToken Standard Fields
43	// -----------------------------------------------------------------------
44	access(all) var totalSupply: UInt64
45	
46	// -----------------------------------------------------------------------
47	// BasicBeasts Fields
48	// -----------------------------------------------------------------------
49	// Generation that a BeastTemplate belongs to.
50	// Generation is a concept that indicates a group of BeastTemplates through time.
51	// Many BeastTemplates can exist at a time, but only one generation.
52	access(all) var currentGeneration: UInt32
53	
54	// Variable size dictionary of beastTemplate structs
55	access(self) var beastTemplates: {UInt32: BeastTemplate}
56	
57	access(self) var retired: {UInt32: Bool}
58	
59	access(self) var numberMintedPerBeastTemplate: {UInt32: UInt32}
60	
61	access(self) var royalties: [MetadataViews.Royalty]
62	
63	access(all) struct BeastTemplate { 
64		access(all) let beastTemplateID: UInt32
65		access(all) let generation: UInt32
66		access(all) let dexNumber: UInt32
67		access(all) let name: String
68		access(all) let description: String
69		access(all) let image: String
70		access(all) let imageTransparentBg: String
71		access(all) let rarity: String
72		access(all) let skin: String
73		access(all) let starLevel: UInt32
74		access(all) let asexual: Bool
75		// The Beast Template ID that can be born from this Beast Template
76		access(all) let breedableBeastTemplateID: UInt32
77		// Maximum mint by Admin allowed
78		access(all) let maxAdminMintAllowed: UInt32
79		access(all) let ultimateSkill: String
80		access(all) let basicSkills: [String]
81		access(all) let elements: [String]
82		access(all) let data:{ String: String}
83		
84		init(beastTemplateID: UInt32, dexNumber: UInt32, name: String, description: String, image: String, imageTransparentBg: String, rarity: String, skin: String, starLevel: UInt32, asexual: Bool, breedableBeastTemplateID: UInt32, maxAdminMintAllowed: UInt32, ultimateSkill: String, basicSkills: [String], elements: [String], data:{ String: String}) { 
85			pre{ 
86				dexNumber > 0:
87					"Cannot initialize new Beast Template: dexNumber cannot be 0"
88				name != "":
89					"Cannot initialize new Beast Template: name cannot be blank"
90				description != "":
91					"Cannot initialize new Beast Template: description cannot be blank"
92				image != "":
93					"Cannot initialize new Beast Template: image cannot be blank"
94				imageTransparentBg != "":
95					"Cannot initialize new Beast Template: imageTransparentBg cannot be blank"
96				rarity != "":
97					"Cannot initialize new Beast Template: rarity cannot be blank"
98				skin != "":
99					"Cannot initialize new Beast Template: skin cannot be blank"
100				ultimateSkill != "":
101					"Cannot initialize new Beast Template: ultimate cannot be blank"
102				basicSkills.length != 0:
103					"Cannot initialize new Beast Template: basicSkills cannot be empty"
104			}
105			self.beastTemplateID = beastTemplateID
106			self.generation = BasicBeasts.currentGeneration
107			self.dexNumber = dexNumber
108			self.name = name
109			self.description = description
110			self.image = image
111			self.imageTransparentBg = imageTransparentBg
112			self.rarity = rarity
113			self.skin = skin
114			self.starLevel = starLevel
115			self.asexual = asexual
116			self.breedableBeastTemplateID = breedableBeastTemplateID
117			self.maxAdminMintAllowed = maxAdminMintAllowed
118			self.ultimateSkill = ultimateSkill
119			self.basicSkills = basicSkills
120			self.elements = elements
121			self.data = data
122		}
123	}
124	
125	access(all) struct BeastNftStruct { 
126		access(all) let id: UInt64
127		access(all) let serialNumber: UInt32
128		access(all) let sex: String
129		access(all) let beastTemplateID: UInt32
130		access(all) let firstOwner: Address?
131		
132		init(id: UInt64, serialNumber: UInt32, sex: String, beastTemplateID: UInt32, firstOwner: Address?) { 
133			self.id = id
134			self.serialNumber = serialNumber
135			self.sex = sex
136			self.beastTemplateID = beastTemplateID
137			self.firstOwner = firstOwner
138		}
139	}
140	
141	access(all) resource interface Public { 
142		access(all) let id: UInt64
143		access(all) let serialNumber: UInt32
144		access(all) let sex: String
145		access(all) let matron: BeastNftStruct?
146		access(all) let sire: BeastNftStruct?
147		access(contract) let beastTemplate: BeastTemplate
148		access(contract) var nickname: String
149		access(contract) var firstOwner: Address?
150		access(contract) let evolvedFrom: [BeastNftStruct]?
151		access(all) fun getBeastTemplate(): BasicBeasts.BeastTemplate
152		access(all) fun getNickname(): String?
153		access(all) fun getFirstOwner(): Address?
154		access(all) fun getEvolvedFrom(): [BeastNftStruct]?
155	}
156	
157	access(all) resource NFT: NonFungibleToken.NFT, Public, ViewResolver.Resolver { 
158
159		access(all) let id: UInt64
160		access(all) let serialNumber: UInt32
161		access(all) let sex: String
162		access(all) let matron: BeastNftStruct?
163		access(all) let sire: BeastNftStruct?
164		access(contract) let beastTemplate: BeastTemplate
165		access(contract) var nickname: String
166		access(contract) var firstOwner: Address?
167		access(contract) let evolvedFrom: [BeastNftStruct]?
168		
169		init(beastTemplateID: UInt32, matron: BeastNftStruct?, sire: BeastNftStruct?, evolvedFrom: [BeastNftStruct]?) { 
170			pre{ 
171				BasicBeasts.beastTemplates[beastTemplateID] != nil:
172					"Cannot mint Beast: Beast Template ID does not exist"
173			}
174			BasicBeasts.totalSupply = BasicBeasts.totalSupply + 1
175			BasicBeasts.numberMintedPerBeastTemplate[beastTemplateID] = BasicBeasts.numberMintedPerBeastTemplate[beastTemplateID]! + 1
176			self.id = self.uuid
177			self.serialNumber = BasicBeasts.numberMintedPerBeastTemplate[beastTemplateID]!
178			var beastTemplate = BasicBeasts.beastTemplates[beastTemplateID]!
179			var sex = "Asexual"
180			if !beastTemplate.asexual{ 
181				// Female or Male depending on the result
182				var probability = 0.5
183				var isFemale = Int(self.uuid) * Int(revertibleRandom<UInt64>()) % 100_000_000 < Int(100_000_000.0 * probability)
184				if isFemale{ 
185					sex = "Female"
186				} else{ 
187					sex = "Male"
188				}
189			}
190			self.sex = sex
191			self.matron = matron
192			self.sire = sire
193			self.beastTemplate = beastTemplate
194			self.nickname = beastTemplate.name
195			self.firstOwner = nil
196			self.evolvedFrom = evolvedFrom
197			emit BeastMinted(id: self.id, address: self.owner?.address, beastTemplateID: self.beastTemplate.beastTemplateID, serialNumber: self.serialNumber, sex: self.sex, matron: self.matron, sire: self.sire)
198		}
199		
200		access(NFTOwner) fun setNickname(nickname: String) { 
201			pre{ 
202				BasicBeasts.validateNickname(nickname: nickname):
203					"Can't change nickname: Nickname is more than 16 characters"
204			}
205			if nickname.length == 0{ 
206				self.nickname = self.beastTemplate.name
207			} else{ 
208				self.nickname = nickname
209			}
210			emit BeastNewNicknameSet(id: self.id, nickname: self.nickname)
211		}
212		
213		// setFirstOwner sets the First Owner of this NFT
214		// this action cannot be undone
215		// 
216		// Parameters: firstOwner: The address of the firstOwner
217		//
218		access(NFTOwner) fun setFirstOwner(firstOwner: Address) { 
219			pre{ 
220				self.firstOwner == nil:
221					"First Owner is already initialized"
222			}
223			self.firstOwner = firstOwner
224			emit BeastFirstOwnerSet(id: self.id, firstOwner: self.firstOwner!)
225		}
226		
227		access(all) fun getBeastTemplate(): BeastTemplate { 
228			return self.beastTemplate
229		}
230		
231		access(all) fun getNickname(): String? { 
232			return self.nickname
233		}
234		
235		access(all) fun getFirstOwner(): Address? { 
236			return self.firstOwner
237		}
238		
239		access(all) fun getEvolvedFrom(): [BeastNftStruct]? { 
240			return self.evolvedFrom
241		}
242		
243		access(all) view fun getViews(): [Type] { 
244			return [Type<MetadataViews.Display>(), Type<MetadataViews.Royalties>(), Type<MetadataViews.Editions>(), Type<MetadataViews.ExternalURL>(), Type<MetadataViews.NFTCollectionData>(), Type<MetadataViews.NFTCollectionDisplay>(), Type<MetadataViews.Serial>(), Type<MetadataViews.Rarity>(), Type<MetadataViews.Traits>()]
245		}
246		
247		access(all) fun resolveView(_ view: Type): AnyStruct? { 
248			switch view{ 
249				case Type<MetadataViews.Display>():
250					return MetadataViews.Display(name: self.nickname, description: self.beastTemplate.description, thumbnail: MetadataViews.IPFSFile(cid: self.beastTemplate.image, path: nil))
251				case Type<MetadataViews.Royalties>():
252					let royalties: [MetadataViews.Royalty] = BasicBeasts.royalties
253					if self.firstOwner != nil{ 
254						royalties.append(MetadataViews.Royalty(receiver: getAccount(self.firstOwner!).capabilities.get<&FlowToken.Vault>(/public/flowTokenReceiver), cut: 0.05, // 5% royalty on secondary sales																																												
255																																												description: "First owner 5% royalty from secondary sales."))
256					}
257					return MetadataViews.Royalties(royalties)
258				case Type<MetadataViews.Editions>():
259					// There is no max number of NFTs that can be minted from this contract
260					// so the max edition field value is set to nil
261					let editionInfo = MetadataViews.Edition(name: "Basic Beasts Edition".concat(" ").concat(self.beastTemplate.name).concat(" ").concat(self.beastTemplate.skin), number: UInt64(self.serialNumber), max: UInt64(BasicBeasts.getNumberMintedPerBeastTemplate(beastTemplateID: self.beastTemplate.beastTemplateID)!))
262					let editionList: [MetadataViews.Edition] = [editionInfo]
263					return MetadataViews.Editions(editionList)
264				case Type<MetadataViews.ExternalURL>():
265					//Get dexNumber in url format e.g. 010, 001, etc.
266					let num: String = "00".concat(self.beastTemplate.dexNumber.toString())
267					let dex: String = num.slice(from: num.length - 3, upTo: num.length)
268					
269					//Get skin in url format e.g. normal, shiny-gold
270					let skin: String = self.beastTemplate.skin.toLower()
271					var skinFormatted: String = ""
272					var i = 0
273					while i < skin.length{ 
274						let char = skin[i]
275						if char == " "{ 
276							skinFormatted = skinFormatted.concat("-")
277						} else{ 
278							skinFormatted = skinFormatted.concat(char.toString())
279						}
280						i = i + 1
281					}
282					return MetadataViews.ExternalURL("https://basicbeasts.io/".concat("beast").concat("/").concat(dex).concat("-").concat(skinFormatted)) // e.g. https://basicbeasts.io/beast/001-cursed-black/
283				
284				case Type<MetadataViews.NFTCollectionData>():
285					return MetadataViews.NFTCollectionData(storagePath: BasicBeasts.CollectionStoragePath, publicPath: BasicBeasts.CollectionPublicPath, publicCollection: Type<&BasicBeasts.Collection>(), publicLinkedType: Type<&BasicBeasts.Collection>(), createEmptyCollectionFunction: fun (): @{NonFungibleToken.Collection}{ 
286							return <-BasicBeasts.createEmptyCollection(nftType: Type<@BasicBeasts.Collection>())
287						})
288				case Type<MetadataViews.NFTCollectionDisplay>():
289					let externalURL = MetadataViews.ExternalURL("https://basicbeasts.io")
290					let squareImage = MetadataViews.Media(file: MetadataViews.IPFSFile(cid: "Qmd9d2EcdfKovAxQVDCgtUXh5RiqhoRRW1HYpg4zN75JND", path: nil), mediaType: "image/png")
291					let bannerImage = MetadataViews.Media(file: MetadataViews.IPFSFile(cid: "QmQXF95pcL9j7wEQAV9NFUiV6NnHRAbD2SZjkpezr3hJgp", path: nil), mediaType: "image/png")
292					let socialMap:{ String: MetadataViews.ExternalURL} ={ "twitter": MetadataViews.ExternalURL("https://twitter.com/basicbeastsnft"), "discord": MetadataViews.ExternalURL("https://discord.com/invite/xgFtWhwSaR")}
293					return MetadataViews.NFTCollectionDisplay(name: "Basic Beasts", description: "Basic Beasts by BB Club DAO", externalURL: externalURL, squareImage: squareImage, bannerImage: bannerImage, socials: socialMap)
294				case Type<MetadataViews.Serial>():
295					return MetadataViews.Serial(UInt64(self.serialNumber))
296				case Type<MetadataViews.Rarity>():
297					var rarity: UFix64 = 0.0
298					var max: UFix64? = nil
299					if self.beastTemplate.starLevel == 1{ 
300						max = UFix64(self.beastTemplate.maxAdminMintAllowed)
301					}
302					switch self.beastTemplate.skin{ 
303						case "Normal":
304							rarity = 1.0
305							max = nil
306						case "Metallic Silver":
307							rarity = 2.0
308							max = nil
309						case "Cursed Black":
310							rarity = 3.0
311						case "Shiny Gold":
312							rarity = 4.0
313						case "Mythic Diamond":
314							rarity = 5.0
315					}
316					if self.beastTemplate.rarity == "Legendary"{ 
317						rarity = rarity + 5.0
318					}
319					return MetadataViews.Rarity(score: rarity, max: max, description: self.beastTemplate.skin)
320				case Type<MetadataViews.Traits>():
321					let traits: [MetadataViews.Trait] = []
322					let skin: MetadataViews.Trait = MetadataViews.Trait(name: "Skin", value: self.beastTemplate.skin, displayType: "String", rarity: nil)
323					traits.append(skin)
324					let dex: MetadataViews.Trait = MetadataViews.Trait(name: "Dex Number", value: self.beastTemplate.dexNumber, displayType: "Number", rarity: nil)
325					traits.append(dex)
326					let starLevel: MetadataViews.Trait = MetadataViews.Trait(name: "Star Level", value: self.beastTemplate.starLevel, displayType: "Number", rarity: nil)
327					traits.append(starLevel)
328					let gender: MetadataViews.Trait = MetadataViews.Trait(name: "Gender", value: self.sex, displayType: "String", rarity: nil)
329					traits.append(gender)
330					let element: MetadataViews.Trait = MetadataViews.Trait(name: "Element", value: self.beastTemplate.elements[0], displayType: "String", rarity: nil)
331					traits.append(element)
332					let gen: MetadataViews.Trait = MetadataViews.Trait(name: "Generation", value: self.beastTemplate.generation, displayType: "Number", rarity: nil)
333					traits.append(gen)
334					return MetadataViews.Traits(traits)
335			}
336			return nil
337		}
338		
339		access(all) fun createEmptyCollection(): @{NonFungibleToken.Collection} { 
340			return <-create Collection()
341		}
342	}
343	
344	// -----------------------------------------------------------------------
345	// Admin Resource Functions
346	//
347	// Admin is a special authorization resource that 
348	// allows the owner to perform important NFT 
349	// functions
350	// -----------------------------------------------------------------------
351	access(all) resource Admin { 
352		access(AdminOwner) fun createBeastTemplate(beastTemplateID: UInt32, dexNumber: UInt32, name: String, description: String, image: String, imageTransparentBg: String, rarity: String, skin: String, starLevel: UInt32, asexual: Bool, breedableBeastTemplateID: UInt32, maxAdminMintAllowed: UInt32, ultimateSkill: String, basicSkills: [String], elements: [String], data:{ String: String}): UInt32 { 
353			pre{ 
354				BasicBeasts.beastTemplates[beastTemplateID] == nil:
355					"Cannot create Beast Template: Beast Template ID already exist"
356				BasicBeasts.numberMintedPerBeastTemplate[beastTemplateID] == nil:
357					"Cannot create Beast Template: Beast Template has already been created"
358			}
359			var newBeastTemplate = BeastTemplate(beastTemplateID: beastTemplateID, dexNumber: dexNumber, name: name, description: description, image: image, imageTransparentBg: imageTransparentBg, rarity: rarity, skin: skin, starLevel: starLevel, asexual: asexual, breedableBeastTemplateID: breedableBeastTemplateID, maxAdminMintAllowed: maxAdminMintAllowed, ultimateSkill: ultimateSkill, basicSkills: basicSkills, elements: elements, data: data)
360			BasicBeasts.retired[beastTemplateID] = false
361			BasicBeasts.numberMintedPerBeastTemplate[beastTemplateID] = 0
362			BasicBeasts.beastTemplates[beastTemplateID] = newBeastTemplate
363			emit BeastTemplateCreated(beastTemplateID: beastTemplateID, name: name, skin: skin)
364			return newBeastTemplate.beastTemplateID
365		}
366		
367		access(AdminOwner) fun mintBeast(beastTemplateID: UInt32): @NFT { 
368			// Admin specific pre-condition for minting a beast
369			pre{ 
370				BasicBeasts.beastTemplates[beastTemplateID] != nil:
371					"Cannot mint Beast: Beast Template ID does not exist"
372				BasicBeasts.numberMintedPerBeastTemplate[beastTemplateID]! < (BasicBeasts.beastTemplates[beastTemplateID]!).maxAdminMintAllowed:
373					"Cannot mint Beast: Max mint by Admin allowance for this Beast is reached"
374			}
375			
376			// When minting genesis beasts. Set matron, sire, evolvedFrom to nil
377			let newBeast: @NFT <- BasicBeasts.mintBeast(beastTemplateID: beastTemplateID, matron: nil, sire: nil, evolvedFrom: nil)
378			return <-newBeast
379		}
380		
381		access(AdminOwner) fun retireBeast(beastTemplateID: UInt32) { 
382			BasicBeasts.retireBeast(beastTemplateID: beastTemplateID)
383		}
384		
385		access(AdminOwner) fun startNewGeneration(): UInt32 { 
386			BasicBeasts.currentGeneration = BasicBeasts.currentGeneration + 1
387			emit NewGenerationStarted(newCurrentGeneration: BasicBeasts.currentGeneration)
388			return BasicBeasts.currentGeneration
389		}
390		
391		access(AdminOwner) fun createNewAdmin(): @Admin { 
392			return <-create Admin()
393		}
394	}
395	
396	access(all) resource interface BeastCollectionPublic { 
397		access(all) fun deposit(token: @{NonFungibleToken.NFT}): Void
398		
399		access(all) view fun getIDs(): [UInt64]
400		
401		access(all) view fun borrowNFT(_ id: UInt64): &{NonFungibleToken.NFT}?
402		
403		access(all) fun borrowBeast(id: UInt64): &BasicBeasts.NFT? { 
404			post{ 
405				result == nil || result?.id == id:
406					"Cannot borrow Beast reference: The ID of the returned reference is incorrect"
407			}
408		}
409	}
410	
411	access(all) resource Collection: BeastCollectionPublic, NonFungibleToken.Provider, NonFungibleToken.Receiver, NonFungibleToken.Collection, NonFungibleToken.CollectionPublic, ViewResolver.ResolverCollection { 
412		access(all) var ownedNFTs: @{UInt64:{ NonFungibleToken.NFT}}
413		
414		init(){ 
415			self.ownedNFTs <-{} 
416		}
417		
418		access(NonFungibleToken.Withdraw) fun withdraw(withdrawID: UInt64): @{NonFungibleToken.NFT} { 
419			let token <- self.ownedNFTs.remove(key: withdrawID) ?? panic("Cannot withdraw: The Beast does not exist in the Collection")
420			emit Withdraw(id: token.id, from: self.owner?.address)
421			return <-token
422		}
423		
424		access(all) fun deposit(token: @{NonFungibleToken.NFT}): Void { 
425			let token <- token as! @BasicBeasts.NFT
426			let id = token.id
427			let oldToken <- self.ownedNFTs[id] <- token
428			if self.owner?.address != nil{ 
429				emit Deposit(id: id, to: self.owner?.address)
430			}
431			destroy oldToken
432		}
433		
434		access(all) view fun getIDs(): [UInt64] { 
435			return self.ownedNFTs.keys
436		}
437		
438		access(all) view fun borrowNFT(_ id: UInt64): &{NonFungibleToken.NFT}? { 
439			return (&self.ownedNFTs[id] as &{NonFungibleToken.NFT}?)!
440		}
441		
442		access(all) view fun borrowBeast(id: UInt64): &BasicBeasts.NFT? { 
443			let ref = &self.ownedNFTs[id] as &{NonFungibleToken.NFT}?
444			return ref as! &BasicBeasts.NFT?
445		}
446		
447		access(NFTOwner) fun borrowEntireBeast(id: UInt64): &BasicBeasts.NFT? {
448			let ref = (&self.ownedNFTs[id] as &{NonFungibleToken.NFT}?)!
449			return ref as! &BasicBeasts.NFT
450		}
451		
452		access(all) view fun borrowViewResolver(id: UInt64): &{ViewResolver.Resolver}? { 
453			let nft = (&self.ownedNFTs[id] as &{NonFungibleToken.NFT}?)!
454			let basicBeastsNFT = nft as! &BasicBeasts.NFT
455			return basicBeastsNFT
456		}
457		
458		access(all) view fun getSupportedNFTTypes():{ Type: Bool} { 
459			return {
460				Type<@BasicBeasts.NFT>(): true
461			}
462		}
463		
464		access(all) view fun isSupportedNFTType(type: Type): Bool { 
465			return type == Type<@BasicBeasts.NFT>()
466		}
467		
468		access(all) fun createEmptyCollection(): @{NonFungibleToken.Collection} { 
469			return <-create Collection()
470		}
471	}
472	
473	// -----------------------------------------------------------------------
474	// Access(Account) Functions
475	// -----------------------------------------------------------------------
476	// Used for all types of minting of beasts: admin minting, evolution minting, and breeding minting
477	access(account) fun mintBeast(beastTemplateID: UInt32, matron: BeastNftStruct?, sire: BeastNftStruct?, evolvedFrom: [BeastNftStruct]?): @NFT { 
478		// Pre-condition that has to be followed regardless of Admin Minting, Evolution Minting, or Breeding Minting.
479		pre{ 
480			BasicBeasts.beastTemplates[beastTemplateID] != nil:
481				"Cannot mint Beast: Beast Template ID does not exist"
482			!BasicBeasts.retired[beastTemplateID]!:
483				"Cannot mint Beast: Beast is retired"
484		}
485		let newBeast: @NFT <- create NFT(beastTemplateID: beastTemplateID, matron: matron, sire: sire, evolvedFrom: evolvedFrom)
486		let skin = newBeast.getBeastTemplate().skin
487		if skin == "Mythic Diamond"{ 
488			BasicBeasts.retireBeast(beastTemplateID: newBeast.getBeastTemplate().beastTemplateID)
489		}
490		return <-newBeast
491	}
492	
493	access(account) fun retireBeast(beastTemplateID: UInt32) { 
494		pre{ 
495			BasicBeasts.retired[beastTemplateID] != nil:
496				"Cannot retire the Beast: The Beast Template ID doesn't exist."
497			(BasicBeasts.beastTemplates[beastTemplateID]!).skin != "Normal":
498				"Cannot retire the Beast: Cannot retire Normal skin beasts."
499		}
500		if !BasicBeasts.retired[beastTemplateID]!{ 
501			BasicBeasts.retired[beastTemplateID] = true
502			emit BeastRetired(beastTemplateID: beastTemplateID, numberMintedPerBeastTemplate: BasicBeasts.numberMintedPerBeastTemplate[beastTemplateID]!)
503		}
504	}
505	
506	// -----------------------------------------------------------------------
507	// Public Functions
508	// -----------------------------------------------------------------------
509	access(all) view fun validateNickname(nickname: String): Bool { 
510		if nickname.length > 16{ 
511			return false
512		}
513		return true
514	}
515	
516	// -----------------------------------------------------------------------
517	// Public Getter Functions
518	// -----------------------------------------------------------------------	
519	access(all) view fun getAllBeastTemplates():{ UInt32: BeastTemplate} { 
520		return self.beastTemplates
521	}
522	
523	access(all) view fun getAllBeastTemplateIDs(): [UInt32] { 
524		return self.beastTemplates.keys
525	}
526	
527	access(all) view fun getBeastTemplate(beastTemplateID: UInt32): BeastTemplate? { 
528		return self.beastTemplates[beastTemplateID]
529	}
530	
531	access(all) view fun getRetiredDictionary():{ UInt32: Bool} { 
532		return self.retired
533	}
534	
535	access(all) view fun getAllRetiredKeys(): [UInt32] { 
536		return self.retired.keys
537	}
538	
539	access(all) view fun isBeastRetired(beastTemplateID: UInt32): Bool? { 
540		return self.retired[beastTemplateID]
541	}
542	
543	access(all) view fun getAllNumberMintedPerBeastTemplate():{ UInt32: UInt32} { 
544		return self.numberMintedPerBeastTemplate
545	}
546	
547	access(all) view fun getAllNumberMintedPerBeastTemplateKeys(): [UInt32] { 
548		return self.numberMintedPerBeastTemplate.keys
549	}
550	
551	access(all) view fun getNumberMintedPerBeastTemplate(beastTemplateID: UInt32): UInt32? { 
552		return self.numberMintedPerBeastTemplate[beastTemplateID]
553	}
554	
555	// -----------------------------------------------------------------------
556	// NonFungibleToken Standard Functions
557	// -----------------------------------------------------------------------
558	access(all) fun createEmptyCollection(nftType: Type): @{NonFungibleToken.Collection} { 
559		return <-create self.Collection()
560	}
561
562	// -----------------------------------------------------------------------
563	// MetadataViews - Purposely Empty
564	// -----------------------------------------------------------------------
565    access(all) fun resolveContractView(resourceType: Type?, viewType: Type): AnyStruct? {
566        return nil
567    }
568
569    access(all) view fun getContractViews(resourceType: Type?): [Type] {
570        return []
571    }
572	
573	init(){ 
574		// Set named paths
575		self.CollectionStoragePath = /storage/BasicBeastsCollection
576		self.CollectionPublicPath = /public/BasicBeastsCollection
577		self.CollectionPrivatePath = /private/BasicBeastsCollection
578		self.AdminStoragePath = /storage/BasicBeastsAdmin
579		self.AdminPrivatePath = /private/BasicBeastsAdminUpgrade
580		
581		// Initialize the fields
582		self.totalSupply = 0
583		self.currentGeneration = 1
584		self.beastTemplates ={} 
585		self.retired ={} 
586		self.numberMintedPerBeastTemplate ={} 
587		self.royalties = [MetadataViews.Royalty(receiver: self.account.capabilities.get<&FlowToken.Vault>(/public/flowTokenReceiver), cut: 0.05, // 5% royalty on secondary sales																																				 
588																																				 description: "Basic Beasts 5% royalty from secondary sales.")]
589		
590		// Put Admin in storage
591		self.account.storage.save(<-create Admin(), to: self.AdminStoragePath)
592		var capability_1 = self.account.capabilities.storage.issue<&BasicBeasts.Admin>(self.AdminStoragePath)
593		emit ContractInitialized()
594	}
595}/*
596	Basic Beasts was initially a simple idea made by a 10-year-old boy in late 2021. 
597	However, this idea would have never come to fruition without the help and support of the community.
598	We are here because of you. Thank you for creating Basic Beasts.
599	
600	bb boy, wb, swt, jake, bz, pan, xpromt, alxo, hsuan, bjartek, unlocked, james, nish, 
601
602	mik, roham, dete, maxstarka, bebner, joshua, kim, albert, chandan, andreh, sonia, 
603
604	gel, morgan, saihaj, techbubble, quin, aivan, kyle, bswides, wheel, yadra, alfredoo, jingtao, 
605	
606	coopervodka, nick, cryptonautik, dotti, fidelio, angelo, maxime, ersin, 17pgts, 
607	flowpark, alpventure, ranger, demarcal, devboi, mokville, 
608	knotbean, nh, chimkenparm, ricky, bam, kelcoin, timon, pavspec, klaimer, 
609	misterzenzi, vovaedet, jegs, lakeshow32, hempdoctor420, ripcityreign, cdavis82, 
610	tonyprofits, scorpius, dankochen, lonestarsmoker, kingkong, v1a0, demisteward, 
611	davep, andy2112, santiago, viktozi, jamesdillonbond, superstar, phoenix, massmike4200, 
612	kozak99, s41ntl3ss, tippah, nunot, qjb, dverity, diabulos, txseppe, cabruhl, 
613	suurikat, eekmanni, echapa, dbone, mikey31, f8xj, packdrip, defkeet, thetafuelz, 
614	elite4max, mrfred, annyongnewman, petethetipsybeet49, abo, jhoem, thekingbeej, 
615	mak, gauchoide, nikitak, kselian, kody2323, carrie, dutts, spyturtle1122, 
616	burntfrito, blutroyal, pooowei, yoghurt4, maxbasev, slackhash, ballinonabudget05, 
617	flowlifer, ahmetbaksi, jjyumyum, ranger, kazimirzenit, bad81, divisionday, svejk, 
618	pyangot, giottoarts, earlyadopter, 54srn54, ninobrown34, sse0321, laguitte, woods, 
619	vkurenkov, valor, vitalyk, groat, duskykoyote, royrumbler, yeahyou27, kybleu, 
620	intoxicaitlyn, nicekid, marci, dhrussel, pennyhoardaway, roaringhammy, smuge, anpol, 
621	kaneluo, valentime, bhrtt, borough, rg, lessthanx3, kizobe9d9, tk24, nokalaka, nftrell, 
622	fragglecar, twix4us, makolacky, charlenek, idinakhuy, thedarkside, wigwag, kel, foulmdp, 
623	bign8ive, unboxinglife, sirmpineapple, hector, cal, mauro06, aguswjy, lorklein, henniganx, 
624	t1les, robocot34, dickson, luba22, sebatessey, robelc, hitsuji, icedragonslayer, 
625	squeakytadpole, papavader, edogg1976, jiexawow, ezweezy, zenyk2, briando, fen, joka, 
626	mr2194, apaxngh, baldmamba, regoisreal, furkangg, bigedude, srchadwick, lild923, and many more.
627	
628	Let's have fun beastkid21!
629
630*/
631
632
633