Smart Contract
BasicBeasts
A.de7a5daf9df48c65.BasicBeasts
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