Smart Contract

Sportvatar

A.ca5c31c0c03e11be.Sportvatar

Deployed

5d ago
Feb 22, 2026, 03:56:58 PM UTC

Dependents

38 imports
1import FungibleToken from 0xf233dcee88fe0abe
2import ViewResolver from 0x1d7e57aa55817448
3import NonFungibleToken from 0x1d7e57aa55817448
4import FlowToken from 0x1654653399040a61
5import SportvatarTemplate from 0xca5c31c0c03e11be
6import MetadataViews from 0x1d7e57aa55817448
7import SportvatarPack from 0xca5c31c0c03e11be
8import Sportbit from 0xca5c31c0c03e11be
9import FlovatarComponentTemplate from 0x921ea449dffec68a
10import FlovatarComponent from 0x921ea449dffec68a
11
12/*
13
14 The contract that defines the Sportvatar NFT and a Collection to manage them
15
16
17This contract contains also the Admin resource that can be used to manage and generate the Sportvatar Templates.
18
19 */
20
21access(all)
22contract Sportvatar: NonFungibleToken{ 
23	access(all)
24	let CollectionStoragePath: StoragePath
25	
26	access(all)
27	let CollectionPublicPath: PublicPath
28	
29	access(all)
30	let AdminStoragePath: StoragePath
31	
32	// These will be used in the Marketplace to pay out
33	// royalties to the creator and to the marketplace
34	access(account)
35	var royaltyCut: UFix64
36	
37	access(account)
38	var marketplaceCut: UFix64
39	
40	// Here we keep track of all the Sportvatar unique combinations and names
41	// that people will generate to make sure that there are no duplicates
42	access(all)
43	var totalSupply: UInt64
44	
45	access(contract)
46	let mintedCombinations:{ String: Bool}
47	
48	access(contract)
49	let mintedNames:{ String: Bool}
50	
51	access(all)
52	event ContractInitialized()
53	
54	access(all)
55	event Withdraw(id: UInt64, from: Address?)
56	
57	access(all)
58	event Deposit(id: UInt64, to: Address?)
59	
60	access(all)
61	event Created(id: UInt64, mint: UInt64, series: UInt64, address: Address)
62	
63	access(all)
64	event Updated(id: UInt64)
65	
66	access(all)
67	event Destroyed(id: UInt64)
68	
69	access(all)
70	event NameSet(id: UInt64, name: String)
71	
72	access(all)
73	event PositionChanged(id: UInt64, position: String)
74	
75	access(all)
76	event StoryAdded(id: UInt64, story: String)
77	
78	access(all)
79	struct Royalties{ 
80		access(all)
81		let royalty: [Royalty]
82		
83		init(royalty: [Royalty]){ 
84			self.royalty = royalty
85		}
86	}
87	
88	access(all)
89	enum RoyaltyType: UInt8{ 
90		access(all)
91		case fixed
92		
93		access(all)
94		case percentage
95	}
96	
97	access(all)
98	struct Royalty{ 
99		access(all)
100		let wallet: Capability<&{FungibleToken.Receiver}>
101		
102		access(all)
103		let cut: UFix64
104		
105		//can be percentage
106		access(all)
107		let type: RoyaltyType
108		
109		init(wallet: Capability<&{FungibleToken.Receiver}>, cut: UFix64, type: RoyaltyType){ 
110			if !wallet.check(){ 
111				panic("Capability not valid!")
112			}
113			self.wallet = wallet
114			self.cut = cut
115			self.type = type
116		}
117	}
118	
119	//Randomize code gently provided by @bluesign
120	access(all)
121	struct RandomInt{ 
122		access(self)
123		var value: UInt64?
124		
125		access(self)
126		let maxValue: UInt64
127		
128		access(self)
129		let minValue: UInt64
130		
131		access(self)
132		let field: String
133		
134		access(self)
135		let uuid: UInt64
136		
137		access(all)
138		init(uuid: UInt64, field: String, minValue: UInt64, maxValue: UInt64){ 
139			self.uuid = uuid
140			self.field = field
141			self.minValue = minValue
142			self.maxValue = maxValue
143			self.value = nil
144		}
145		
146		access(all)
147		fun getValue(): UInt64{ 
148			if let value = self.value{ 
149				return value
150			}
151			let h: [UInt8] = HashAlgorithm.SHA3_256.hash(self.uuid.toBigEndianBytes())
152			let f: [UInt8] = HashAlgorithm.SHA3_256.hash(self.field.utf8)
153			var id = (getBlock(at: getCurrentBlock().height)!).id
154			var random: UInt64 = 0
155			var i = 0
156			while i < 8{ 
157				random = random + (UInt64(id[i]) ^ UInt64(h[i]) ^ UInt64(f[i]))
158				random = random << 8
159				i = i + 1
160			}
161			self.value = self.minValue + random % (self.maxValue - self.minValue)
162			return self.minValue + random % (self.maxValue - self.minValue)
163		}
164	}
165	
166	// The public interface can show metadata and the content for the Sportvatar.
167	// In addition to it, it provides methods to access the additional optional
168	// components (accessory, hat, eyeglasses, background) for everyone.
169	access(all)
170	resource interface Public{ 
171		access(all)
172		let id: UInt64
173		
174		access(all)
175		let mint: UInt64
176		
177		access(all)
178		let series: UInt64
179		
180		access(all)
181		let combination: String
182		
183		access(all)
184		let rarity: String
185		
186		access(all)
187		let creatorAddress: Address
188		
189		access(all)
190		let createdAt: UFix64
191		
192		access(all)
193		let createdAtBlock: UInt64
194		
195		access(contract)
196		let royalties: Royalties
197		
198		// these three are added because I think they will be in the standard. At least Dieter thinks it will be needed
199		access(contract)
200		var name: String
201		
202		access(all)
203		let description: String
204		
205		access(all)
206		let schema: String?
207		
208		access(all)
209		fun getName(): String
210		
211		access(all)
212		fun getSvg(): String
213		
214		access(all)
215		fun getRoyalties(): Royalties
216		
217		access(all)
218		fun getBio():{ String: String}
219		
220		access(all)
221		fun getMetadata():{ String: String}
222		
223		access(all)
224		fun getStats():{ String: UInt32}
225		
226		access(all)
227		fun getLayers():{ UInt32: UInt64?}
228		
229		access(all)
230		fun getAccessories(): [UInt64]
231		
232		access(all)
233		fun getSeries(): SportvatarTemplate.SeriesData?
234		
235		access(all)
236		fun getFlovatarBackground(): UInt64?
237	}
238	
239	//The private interface can update the Accessory, Hat, Eyeglasses and Background
240	//for the Sportvatar and is accessible only to the owner of the NFT
241	access(all)
242	resource interface Private{ 
243		access(all)
244		fun setName(name: String): String
245		
246		access(all)
247		fun addStory(text: String): String
248		
249		access(all)
250		fun setPosition(latitude: Fix64, longitude: Fix64): String
251		
252		access(all)
253		fun setSportbit(layer: UInt32, sportbit: @Sportbit.NFT): @Sportbit.NFT?
254		
255		access(all)
256		fun removeAccessory(layer: UInt32): @Sportbit.NFT?
257		
258		access(all)
259		fun setFlovatarBackground(component: @FlovatarComponent.NFT): @FlovatarComponent.NFT?
260		
261		access(all)
262		fun removeFlovatarBackground(): @FlovatarComponent.NFT?
263	}
264	
265	//The NFT resource that implements both Private and Public interfaces
266	access(all)
267	resource NFT: NonFungibleToken.NFT, Public, Private, ViewResolver.Resolver{ 
268		access(all)
269		let id: UInt64
270		
271		access(all)
272		let mint: UInt64
273		
274		access(all)
275		let series: UInt64
276		
277		access(all)
278		let combination: String
279		
280		access(all)
281		let rarity: String
282		
283		access(all)
284		let creatorAddress: Address
285		
286		access(all)
287		let createdAt: UFix64
288		
289		access(all)
290		let createdAtBlock: UInt64
291		
292		access(contract)
293		let royalties: Royalties
294		
295		access(contract)
296		var name: String
297		
298		access(all)
299		let description: String
300		
301		access(all)
302		let schema: String?
303		
304		access(self)
305		let bio:{ String: String}
306		
307		access(self)
308		let metadata:{ String: String}
309		
310		access(self)
311		let stats:{ String: UInt32}
312		
313		access(self)
314		let layers:{ UInt32: UInt64?}
315		
316		access(self)
317		let accessories: @{UInt32: Sportbit.NFT}
318		
319		access(contract)
320		var background: @FlovatarComponent.NFT?
321		
322		init(series: UInt64, layers:{ UInt32: UInt64?}, metadata:{ String: String}, stats:{ String: UInt32}, creatorAddress: Address, royalties: Royalties, rarity: String){ 
323			Sportvatar.totalSupply = Sportvatar.totalSupply + UInt64(1)
324			SportvatarTemplate.increaseTotalMintedCollectibles(series: series)
325			let coreLayers:{ UInt32: UInt64} = Sportvatar.getCoreLayers(series: series, layers: layers)
326			self.id = Sportvatar.totalSupply
327			self.mint = SportvatarTemplate.getTotalMintedCollectibles(series: series)!
328			self.series = series
329			self.combination = Sportvatar.getCombinationString(series: series, layers: coreLayers)
330			self.creatorAddress = creatorAddress
331			self.createdAt = getCurrentBlock().timestamp
332			self.createdAtBlock = getCurrentBlock().height
333			self.royalties = royalties
334			self.schema = nil
335			self.name = ""
336			self.description = ""
337			self.bio ={} 
338			self.metadata = metadata
339			self.stats = stats
340			self.layers = layers
341			self.accessories <-{} 
342			self.rarity = rarity
343			self.background <- nil
344		}
345		
346		access(all)
347		fun getID(): UInt64{ 
348			return self.id
349		}
350		
351		access(all)
352		fun getMetadata():{ String: String}{ 
353			return self.metadata
354		}
355		
356		access(all)
357		fun getStats():{ String: UInt32}{ 
358			return self.createdAtBlock < getCurrentBlock().height ? self.stats :{} 
359		}
360		
361		access(all)
362		fun getRoyalties(): Royalties{ 
363			return self.royalties
364		}
365		
366		access(all)
367		fun getBio():{ String: String}{ 
368			return self.bio
369		}
370		
371		access(all)
372		fun getName(): String{ 
373			return self.name
374		}
375		
376		access(all)
377		fun getSeries(): SportvatarTemplate.SeriesData?{
378			return SportvatarTemplate.getSeries(id: self.series)
379		}
380		
381		// This will allow to change the Name of the Sportvatar only once.
382		// It checks for the current name is empty, otherwise it will throw an error.
383		access(all)
384		fun setName(name: String): String{ 
385			pre{ 
386				// TODO: Make sure that the text of the name is sanitized
387				//and that bad words are not accepted?
388				name.length > 2:
389					"The name is too short"
390				name.length < 32:
391					"The name is too long"
392				self.name == "":
393					"The name has already been set"
394			//vault.balance == 100.0 : "The amount of $DUST is not correct"
395			//vault.isInstance(Type<@SportvatarDustToken.Vault>()) : "Vault not of the right Token Type"
396			}
397			
398			// Makes sure that the name is available and not taken already
399			if Sportvatar.checkNameAvailable(name: name) == false{ 
400				panic("This name has already been taken")
401			}
402			
403			//destroy vault
404			//self.name = name
405			
406			// Adds the name to the array to remember it
407			//Sportvatar.addMintedName(name: name)
408			//emit NameSet(id: self.id, name: name)
409			return self.name
410		}
411		
412		// This will allow to add a text Story to the Sportvatar Bio.
413		// The String will be concatenated each time.
414		// There is a limit of 300 characters per story but there is no limit in the full concatenated story length
415		access(all)
416		fun addStory(text: String): String{ 
417			pre{ 
418				// TODO: Make sure that the text of the name is sanitized
419				//and that bad words are not accepted?
420				text.length > 0:
421					"The text is too short"
422				text.length <= 300:
423					"The text is too long"
424			//vault.balance == 50.0 : "The amount of $DUST is not correct"
425			//vault.isInstance(Type<@SportvatarDustToken.Vault>()) : "Vault not of the right Token Type"
426			}
427			
428			//destroy vault
429			//let currentStory: String = self.bio["story"] ?? ""
430			//let story: String = currentStory.concat(" ").concat(text)
431			//self.bio.insert(key: "story", story)
432			
433			//emit StoryAdded(id: self.id, story: story)
434			
435			//return story
436			return ""
437		}
438		
439		// This will allow to set the GPS location of a Sportvatar
440		// It can be run multiple times and each time it will override the previous state
441		access(all)
442		fun setPosition(latitude: Fix64, longitude: Fix64): String{ 
443			pre{ 
444				latitude >= -90.0:
445					"The latitude is out of range"
446				latitude <= 90.0:
447					"The latitude is out of range"
448				longitude >= -180.0:
449					"The longitude is out of range"
450				longitude <= 180.0:
451					"The longitude is out of range"
452			//vault.balance == 10.0 : "The amount of $DUST is not correct"
453			//vault.isInstance(Type<@SportvatarDustToken.Vault>()) : "Vault not of the right Token Type"
454			}
455			
456			//destroy vault
457			//let position: String = latitude.toString().concat(",").concat(longitude.toString())
458			//self.bio.insert(key: "position", position)
459			
460			//emit PositionChanged(id: self.id, position: position)
461			
462			//return position
463			return ""
464		}
465		
466		access(all)
467		fun getLayers():{ UInt32: UInt64?}{ 
468			return self.layers
469		}
470		
471		access(all)
472		fun getAccessories(): [UInt64]{ 
473			let accessoriesIds: [UInt64] = []
474			for k in self.accessories.keys{ 
475				let accessoryId = self.accessories[k]?.id
476				if accessoryId != nil{ 
477					accessoriesIds.append(accessoryId!)
478				}
479			}
480			return accessoriesIds
481		}
482		
483		// This will allow to change the Accessory of the Sportvatar any time.
484		// It checks for the right category and series before executing.
485		access(all)
486		fun setSportbit(layer: UInt32, sportbit: @Sportbit.NFT): @Sportbit.NFT?{ 
487
488			if(sportbit.getSeries() != self.series) {
489			    panic("The accessory belongs to a different series")
490			}
491			if SportvatarTemplate.isCollectibleLayerAccessory(layer: layer, series: self.series){ 
492				emit Updated(id: self.id)
493				self.layers[layer] = sportbit.templateId
494				let oldAccessory <- self.accessories[layer] <- sportbit
495				return <-oldAccessory
496			}
497			panic("The Layer is out of range or it's not an accessory")
498		}
499		
500		// This will allow to remove the Accessory of the Sportvatar any time.
501		access(all)
502		fun removeAccessory(layer: UInt32): @Sportbit.NFT?{ 
503			if SportvatarTemplate.isCollectibleLayerAccessory(layer: layer, series: self.series){ 
504				emit Updated(id: self.id)
505				self.layers[layer] = nil
506				let accessory <- self.accessories[layer] <- nil
507				return <-accessory
508			}
509			panic("The Layer is out of range or it's not an accessory")
510		}
511		
512		access(all)
513		fun getFlovatarBackground(): UInt64?{ 
514			return self.background?.templateId
515		}
516		
517		// This will allow to change the Background of the Flobot any time.
518		// It checks for the right category and series before executing.
519		access(all)
520		fun setFlovatarBackground(component: @FlovatarComponent.NFT): @FlovatarComponent.NFT?{
521			if(component.getCategory() != "background"){
522			    panic("The component needs to be a background")
523			}
524			emit Updated(id: self.id)
525			let compNFT <- self.background <- component
526			return <-compNFT
527		}
528		
529		// This will allow to remove the Background of the Flobot any time.
530		access(all)
531		fun removeFlovatarBackground(): @FlovatarComponent.NFT?{ 
532			emit Updated(id: self.id)
533			let compNFT <- self.background <- nil
534			return <-compNFT
535		}
536		
537		// This function will return the full SVG of the Sportvatar. It will take the
538		// optional Background and the other Sportbit components from their
539		// original Template resources, while all the other unmutable components are
540		// taken from the Metadata directly.
541		access(all)
542		fun getSvg(): String{ 
543			let series = SportvatarTemplate.getSeries(id: self.series)
544			let layersArr: [String] = []
545			for k in (series!).layers.keys{ 
546				layersArr.append("")
547			}
548			var svg: String = (series!).svgPrefix
549			if let background = self.getFlovatarBackground(){ 
550				if let template = FlovatarComponentTemplate.getComponentTemplate(id: background){ 
551					svg = svg.concat(template.svg!)
552				}
553			}
554			for k in self.layers.keys{ 
555				if self.layers[k] != nil{ 
556					let layer = self.layers[k]!
557					if layer != nil{ 
558						let tempSvg = SportvatarTemplate.getTemplateSvg(id: layer!)
559						//svg = svg.concat(tempSvg!)
560						layersArr[k - UInt32(1)] = tempSvg!
561					}
562				}
563			}
564			for tempLayer in layersArr{ 
565				svg = svg.concat(tempLayer)
566			}
567			svg = svg.concat((series!).svgSuffix)
568			return svg
569		}
570		
571		access(all)
572		view fun getViews(): [Type]{ 
573			return [
574                Type<MetadataViews.NFTCollectionData>(),
575                Type<MetadataViews.NFTCollectionDisplay>(),
576                Type<MetadataViews.Display>(),
577                Type<MetadataViews.Royalties>(),
578                Type<MetadataViews.Edition>(),
579                Type<MetadataViews.ExternalURL>(),
580                Type<MetadataViews.Serial>(),
581                Type<MetadataViews.Traits>()
582			]
583		}
584		
585		access(all)
586		fun resolveView(_ type: Type): AnyStruct?{ 
587			if type == Type<MetadataViews.ExternalURL>(){ 
588				return MetadataViews.ExternalURL("https://sportvatar.com/collectible/".concat(self.id.toString()))
589			}
590			if type == Type<MetadataViews.Royalties>(){ 
591				let royalties: [MetadataViews.Royalty] = []
592				var count: Int = 0
593				for royalty in self.royalties.royalty{ 
594					royalties.append(MetadataViews.Royalty(receiver: royalty.wallet, cut: royalty.cut, description: "Sportvatar Royalty ".concat(count.toString())))
595					count = count + Int(1)
596				}
597				return MetadataViews.Royalties(royalties)
598			}
599			if type == Type<MetadataViews.Serial>(){ 
600				return MetadataViews.Serial(self.id)
601			}
602			if type == Type<MetadataViews.Editions>(){ 
603				let series = self.getSeries()
604				var maxMintable: UInt64 = (series!).maxMintable
605				if maxMintable == UInt64(0){ 
606					maxMintable = UInt64(999999)
607				}
608				let editionInfo = MetadataViews.Edition(name: "Sportvatar Series ".concat(self.series.toString()), number: self.mint, max: maxMintable)
609				let editionList: [MetadataViews.Edition] = [editionInfo]
610				return MetadataViews.Editions(editionList)
611			}
612			if type == Type<MetadataViews.NFTCollectionDisplay>(){ 
613				let mediaSquare = MetadataViews.Media(file: MetadataViews.HTTPFile(url: "https://images.sportvatar.com/logo.svg"), mediaType: "image/svg+xml")
614				let mediaBanner = MetadataViews.Media(file: MetadataViews.HTTPFile(url: "https://images.sportvatar.com/logo-horizontal.svg"), mediaType: "image/svg+xml")
615				return MetadataViews.NFTCollectionDisplay(name: "Sportvatar Collectible", description: "Sportvatar is the next generation of composable and customizable Digital Collectibles", externalURL: MetadataViews.ExternalURL("https://sportvatar.com"), squareImage: mediaSquare, bannerImage: mediaBanner, socials:{ "discord": MetadataViews.ExternalURL("https://discord.gg/sportvatar"), "twitter": MetadataViews.ExternalURL("https://twitter.com/sportvatar"), "instagram": MetadataViews.ExternalURL("https://instagram.com/sportvatar_nft"), "tiktok": MetadataViews.ExternalURL("https://www.tiktok.com/@sportvatar")})
616			}
617			if type == Type<MetadataViews.Display>(){ 
618				return MetadataViews.Display(name: self.name == "" ? "Sportvatar #".concat(self.id.toString()) : self.name, description: self.description, thumbnail: MetadataViews.HTTPFile(url: "https://images.sportvatar.com/sportvatar/svg/".concat(self.id.toString()).concat(".svg")))
619			}
620			if type == Type<MetadataViews.Traits>(){ 
621				let traits: [MetadataViews.Trait] = []
622				let series = self.getSeries()
623				for k in self.layers.keys{ 
624					if self.layers[k] != nil{ 
625						let layer = (series!).layers[k]!
626						if self.layers[k] != nil{ 
627							let layerSelf = self.layers[k]!
628							if layer != nil{ 
629								let template = SportvatarTemplate.getTemplate(id: layerSelf!)
630								let trait = MetadataViews.Trait(name: (layer!).name, value: (template!).name, displayType: "String", rarity: MetadataViews.Rarity(score: nil, max: nil, description: (template!).rarity))
631								traits.append(trait)
632							}
633						}
634					}
635				}
636				return MetadataViews.Traits(traits)
637			}
638			if type == Type<MetadataViews.NFTCollectionData>(){ 
639				return MetadataViews.NFTCollectionData(storagePath: Sportvatar.CollectionStoragePath, publicPath: Sportvatar.CollectionPublicPath, publicCollection: Type<&Sportvatar.Collection>(), publicLinkedType: Type<&Sportvatar.Collection>(), createEmptyCollectionFunction: fun (): @{NonFungibleToken.Collection}{ 
640						return <-Sportvatar.createEmptyCollection(nftType: Type<@Sportvatar.Collection>())
641					})
642			}
643			return nil
644		}
645		
646		access(all)
647		fun createEmptyCollection(): @{NonFungibleToken.Collection}{ 
648			return <-create Collection()
649		}
650	}
651	
652	// Standard NFT collectionPublic interface that can also borrowSportvatar as the correct type
653	access(all)
654	resource interface CollectionPublic{ 
655		access(all)
656		fun deposit(token: @{NonFungibleToken.NFT})
657		
658		access(all)
659		fun getIDs(): [UInt64]
660		
661		access(all)
662		view fun borrowNFT(_ id: UInt64): &{NonFungibleToken.NFT}?
663		
664		access(all)
665		fun borrowSportvatar(id: UInt64): &Sportvatar.NFT?{ 
666			// If the result isn't nil, the id of the returned reference
667			// should be the same as the argument to the function
668			post{ 
669				result == nil || result?.id == id:
670					"Cannot borrow Sportvatar Dust Collectible reference: The ID of the returned reference is incorrect"
671			}
672		}
673	}
674	
675	// Main Collection to manage all the Sportvatar NFT
676	access(all)
677	resource Collection: CollectionPublic, NonFungibleToken.Provider, NonFungibleToken.Receiver, NonFungibleToken.Collection, NonFungibleToken.CollectionPublic, ViewResolver.ResolverCollection{ 
678		// dictionary of NFT conforming tokens
679		// NFT is a resource type with an `UInt64` ID field
680		access(all)
681		var ownedNFTs: @{UInt64:{ NonFungibleToken.NFT}}
682		
683		init(){ 
684			self.ownedNFTs <-{} 
685		}
686		
687		// withdraw removes an NFT from the collection and moves it to the caller
688		access(NonFungibleToken.Withdraw)
689		fun withdraw(withdrawID: UInt64): @{NonFungibleToken.NFT}{ 
690			let token <- self.ownedNFTs.remove(key: withdrawID) ?? panic("missing NFT")
691			emit Withdraw(id: token.id, from: self.owner?.address)
692			return <-token
693		}
694		
695		// deposit takes a NFT and adds it to the collections dictionary
696		// and adds the ID to the id array
697		access(all)
698		fun deposit(token: @{NonFungibleToken.NFT}){ 
699			let token <- token as! @Sportvatar.NFT
700			let id: UInt64 = token.id
701			
702			// add the new token to the dictionary which removes the old one
703			let oldToken <- self.ownedNFTs[id] <- token
704			emit Deposit(id: id, to: self.owner?.address)
705			destroy oldToken
706		}
707		
708		// getIDs returns an array of the IDs that are in the collection
709		access(all)
710		view fun getIDs(): [UInt64]{ 
711			return self.ownedNFTs.keys
712		}
713		
714		// borrowNFT gets a reference to an NFT in the collection
715		// so that the caller can read its metadata and call its methods
716		access(all)
717		view fun borrowNFT(_ id: UInt64): &{NonFungibleToken.NFT}?{ 
718			return (&self.ownedNFTs[id] as &{NonFungibleToken.NFT}?)!
719		}
720		
721		// borrowSportvatar returns a borrowed reference to a Sportvatar
722		// so that the caller can read data and call methods from it.
723		access(all)
724		fun borrowSportvatar(id: UInt64): &Sportvatar.NFT?{ 
725			if self.ownedNFTs[id] != nil{ 
726				let ref = (&self.ownedNFTs[id] as &{NonFungibleToken.NFT}?)!
727				let collectibleNFT = ref as! &Sportvatar.NFT
728				return collectibleNFT as &Sportvatar.NFT
729			} else{ 
730				return nil
731			}
732		}
733		
734		// borrowSportvatarPrivate returns a borrowed reference to a Sportvatar using the Private interface
735		// so that the caller can read data and call methods from it, like setting the optional components.
736		access(all)
737		fun borrowSportvatarPrivate(id: UInt64): &{Sportvatar.Private}?{ 
738			if self.ownedNFTs[id] != nil{ 
739				let ref = (&self.ownedNFTs[id] as &{NonFungibleToken.NFT}?)!
740				return ref as! &Sportvatar.NFT
741			} else{ 
742				return nil
743			}
744		}
745		
746		access(all)
747		view fun borrowViewResolver(id: UInt64): &{ViewResolver.Resolver}?{ 
748			pre{ 
749				self.ownedNFTs[id] != nil:
750					"NFT does not exist"
751			}
752			let nft = (&self.ownedNFTs[id] as &{NonFungibleToken.NFT}?)!
753			let collectibleNFT = nft as! &Sportvatar.NFT
754			return collectibleNFT as &{ViewResolver.Resolver}
755		}
756		
757		access(all)
758		view fun getSupportedNFTTypes():{ Type: Bool}{ 
759			panic("implement me")
760		}
761		
762		access(all)
763		view fun isSupportedNFTType(type: Type): Bool{ 
764			panic("implement me")
765		}
766		
767		access(all)
768		fun createEmptyCollection(): @{NonFungibleToken.Collection}{ 
769			return <-create Collection()
770		}
771	}
772	
773	// public function that anyone can call to create a new empty collection
774	access(all)
775	fun createEmptyCollection(nftType: Type): @{NonFungibleToken.Collection}{ 
776		return <-create Collection()
777	}
778
779
780
781
782
783	access(all)
784	view fun getContractViews(resourceType: Type?): [Type] {
785		return [
786			Type<MetadataViews.NFTCollectionData>(),
787			Type<MetadataViews.NFTCollectionDisplay>(),
788			Type<MetadataViews.EVMBridgedMetadata>()
789		]
790	}
791
792
793	access(all) fun resolveContractView(resourceType: Type?, viewType: Type): AnyStruct? {
794		switch viewType {
795			case Type<MetadataViews.NFTCollectionData>():
796				let collectionData = MetadataViews.NFTCollectionData(
797					storagePath: self.CollectionStoragePath,
798					publicPath: self.CollectionPublicPath,
799					publicCollection: Type<&Sportvatar.Collection>(),
800					publicLinkedType: Type<&Sportvatar.Collection>(),
801					createEmptyCollectionFunction: (fun(): @{NonFungibleToken.Collection} {
802						return <-Sportvatar.createEmptyCollection(nftType: Type<@Sportvatar.NFT>())
803					})
804				)
805				return collectionData
806			case Type<MetadataViews.NFTCollectionDisplay>():
807				let media = MetadataViews.Media(
808					file: MetadataViews.HTTPFile(
809						url: "https://images.sportvatar.com/logo.svg"
810					),
811					mediaType: "image/svg+xml"
812				)
813				let mediaBanner = MetadataViews.Media(
814					file: MetadataViews.HTTPFile(
815						url: "https://images.sportvatar.com/logo-horizontal.svg"
816					),
817					mediaType: "image/svg+xml"
818				)
819				return MetadataViews.NFTCollectionDisplay(
820					name: "Sportvatar Collection",
821					description: "Sportvatar is the next generation of composable and customizable Digital Collectibles",
822					externalURL: MetadataViews.ExternalURL("https://sportvatar.com"),
823					squareImage: media,
824					bannerImage: mediaBanner,
825					socials: {
826						"twitter": MetadataViews.ExternalURL("https://x.com/sportvatar"),
827						"discord": MetadataViews.ExternalURL("https://discord.gg/sportvatar"),
828						"instagram": MetadataViews.ExternalURL("https://instagram.com/sportvatar"),
829						"tiktok": MetadataViews.ExternalURL("https://www.tiktok.com/@sportvatar")
830					}
831				)
832			case Type<MetadataViews.EVMBridgedMetadata>():
833				// Implementing this view gives the project control over how the bridged NFT is represented as an ERC721
834				// when bridged to EVM on Flow via the public infrastructure bridge.
835
836				// Compose the contract-level URI. In this case, the contract metadata is located on some HTTP host,
837				// but it could be IPFS, S3, a data URL containing the JSON directly, etc.
838				return MetadataViews.EVMBridgedMetadata(
839					name: "Sportvatar",
840					symbol: "SPTV",
841					uri: MetadataViews.URI(
842						baseURI: nil, // setting baseURI as nil sets the given value as the uri field value
843						value: "https://sportvatar.com"
844					)
845				)
846		}
847		return nil
848	}
849
850
851
852
853	
854	// This struct is used to send a data representation of the Sportvatar Dust Collectibles
855	// when retrieved using the contract helper methods outside the collection.
856	access(all)
857	struct SportvatarData{ 
858		access(all)
859		let id: UInt64
860		
861		access(all)
862		let mint: UInt64
863		
864		access(all)
865		let series: UInt64
866		
867		access(all)
868		let name: String
869		
870		access(all)
871		let rarity: String
872		
873		access(all)
874		let svg: String?
875		
876		access(all)
877		let combination: String
878		
879		access(all)
880		let creatorAddress: Address
881		
882		access(all)
883		let layers:{ UInt32: UInt64?}
884		
885		access(all)
886		let bio:{ String: String}
887		
888		access(all)
889		let metadata:{ String: String}
890		
891		access(all)
892		let stats:{ String: UInt32}
893		
894		init(id: UInt64, mint: UInt64, series: UInt64, name: String, rarity: String, svg: String?, combination: String, creatorAddress: Address, layers:{ UInt32: UInt64?}, bio:{ String: String}, metadata:{ String: String}, stats:{ String: UInt32}){ 
895			self.id = id
896			self.mint = mint
897			self.series = series
898			self.name = name
899			self.rarity = rarity
900			self.svg = svg
901			self.combination = combination
902			self.creatorAddress = creatorAddress
903			self.layers = layers
904			self.bio = bio
905			self.metadata = metadata
906			self.stats = stats
907		}
908	}
909	
910	// This function will look for a specific Sportvatar on a user account and return a SportvatarData if found
911	access(all)
912	fun getSportvatar(address: Address, sportvatarId: UInt64): SportvatarData?{ 
913		let account = getAccount(address)
914		if let collectibleCollection = account.capabilities.borrow<&Sportvatar.Collection>(Sportvatar.CollectionPublicPath){
915			if let collectible = collectibleCollection.borrowSportvatar(id: sportvatarId){ 
916				return SportvatarData(id: sportvatarId, mint: (collectible!).mint, series: (collectible!).series, name: (collectible!).getName(), rarity: (collectible!).rarity, svg: (collectible!).getSvg(), combination: (collectible!).combination, creatorAddress: (collectible!).creatorAddress, layers: (collectible!).getLayers(), bio: (collectible!).getBio(), metadata: (collectible!).getMetadata(), stats: (collectible!).getStats())
917			}
918		}
919		return nil
920	}
921	
922	// This function will return all Sportvatars on a user account and return an array of SportvatarData
923	access(all)
924	fun getSportvatars(address: Address): [SportvatarData]{ 
925		var sportvatarData: [SportvatarData] = []
926		let account = getAccount(address)
927		if let collectibleCollection = account.capabilities.borrow<&Sportvatar.Collection>(Sportvatar.CollectionPublicPath){
928			for id in collectibleCollection.getIDs(){ 
929				if let collectible = collectibleCollection.borrowSportvatar(id: id){ 
930					sportvatarData.append(SportvatarData(id: id, mint: (collectible!).mint, series: (collectible!).series, name: (collectible!).getName(), rarity: (collectible!).rarity, svg: nil, combination: (collectible!).combination, creatorAddress: (collectible!).creatorAddress, layers: (collectible!).getLayers(), bio: (collectible!).getBio(), metadata: (collectible!).getMetadata(), stats: (collectible!).getStats()))
931				}
932			}
933		}
934		return sportvatarData
935	}
936	
937	// This returns all the previously minted combinations, so that duplicates won't be allowed
938	access(all)
939	fun getMintedCombinations(): [String]{ 
940		return Sportvatar.mintedCombinations.keys
941	}
942	
943	// This returns all the previously minted names, so that duplicates won't be allowed
944	access(all)
945	fun getMintedNames(): [String]{ 
946		return Sportvatar.mintedNames.keys
947	}
948	
949	// This function will add a minted combination to the array
950	access(account)
951	fun addMintedCombination(combination: String){ 
952		Sportvatar.mintedCombinations.insert(key: combination, true)
953	}
954	
955	// This function will add a new name to the array
956	access(account)
957	fun addMintedName(name: String){ 
958		Sportvatar.mintedNames.insert(key: name, true)
959	}
960	
961	access(all)
962	fun getCoreLayers(series: UInt64, layers:{ UInt32: UInt64?}):{ UInt32: UInt64}{ 
963		let coreLayers:{ UInt32: UInt64} ={} 
964		for k in layers.keys{ 
965			if !SportvatarTemplate.isCollectibleLayerAccessory(layer: k, series: series){ 
966				let templateId = layers[k]!
967				let template = SportvatarTemplate.getTemplate(id: templateId!)!
968				if template.series != series{ 
969					panic("Template belonging to the wrong Dust Collectible Series")
970				}
971				if template.layer != k{ 
972					panic("Template belonging to the wrong Layer")
973				}
974				coreLayers[k] = templateId!
975			}
976		}
977		return coreLayers
978	}
979	
980	// This helper function will generate a string from a list of components,
981	// to be used as a sort of barcode to keep the inventory of the minted
982	// Sportvatars and to avoid duplicates
983	access(all)
984	fun getCombinationString(series: UInt64, layers:{ UInt32: UInt64}): String{ 
985		var combination: String = "S".concat(series.toString())
986		var i: UInt32 = UInt32(2)
987		while i < UInt32(9){ 
988			let layer = layers[i]!
989			combination = combination.concat("-L").concat(i.toString()).concat("_").concat(layer.toString())
990			i = i + UInt32(1)
991		}
992		return combination
993	}
994	
995	// This function will get a list of component IDs and will check if the
996	// generated string is unique or if someone already used it before.
997	access(all)
998	fun checkCombinationAvailable(series: UInt64, layers:{ UInt32: UInt64}): Bool{ 
999		let combinationString = Sportvatar.getCombinationString(series: series, layers: layers)
1000		return !Sportvatar.mintedCombinations.containsKey(combinationString)
1001	}
1002	
1003	// This will check if a specific Name has already been taken
1004	// and assigned to some Sportvatar
1005	access(all)
1006	fun checkNameAvailable(name: String): Bool{ 
1007		return name.length > 2 && name.length < 20 && !Sportvatar.mintedNames.containsKey(name)
1008	}
1009	
1010	// This is a public function that anyone can call to generate a new Sportvatar
1011	// A list of components resources needs to be passed to executed.
1012	// It will check first for uniqueness of the combination + name and will then
1013	// generate the Sportvatar and burn all the passed components.
1014	// The Flame NFT will entitle to use any common basic component (body, hair, etc.)
1015	// In order to use special rare components a boost of the same rarity will be needed
1016	// for each component used
1017	access(all)
1018	fun createSportvatar(sportflame: @Sportbit.NFT, series: UInt64, layers: [UInt32], templateIds: [UInt64?], sportbits: @[Sportbit.NFT?], address: Address): @Sportvatar.NFT{ 
1019		let seriesData = SportvatarTemplate.getSeries(id: series)
1020		if seriesData == nil{ 
1021			panic("Dust Collectible Series not found!")
1022		}
1023		if (seriesData!).layers.length != layers.length{ 
1024			panic("The amount of layers is not matching!")
1025		}
1026		if templateIds.length != layers.length{ 
1027			panic("The amount of layers and templates is not matching!")
1028		}
1029		let mintedCollectibles = SportvatarTemplate.getTotalMintedCollectibles(series: series)
1030		if mintedCollectibles != nil{ 
1031			if (seriesData!).maxMintable > UInt64(0) && mintedCollectibles! >= (seriesData!).maxMintable{ 
1032				panic("Reached the maximum mint number for this Series!")
1033			}
1034		}
1035		let templates: [SportvatarTemplate.TemplateData] = []
1036		let coreLayers:{ UInt32: UInt64} ={} 
1037		let fullLayers:{ UInt32: UInt64?} ={} 
1038		let flameRarity: String = sportflame.getRarity()
1039		let metadata:{ String: String} ={} 
1040		let stats:{ String: UInt32} ={} 
1041		if sportflame.getLayer() != UInt32(0){ 
1042			panic("The Sport Flame belongs to the wrong category")
1043		}
1044		if sportflame.getSeries() != series{ 
1045			panic("The Sport Flame doesn't belong to the correct series")
1046		}
1047		var i: UInt32 = UInt32(0)
1048		while i < UInt32(layers.length){ 
1049			let layerId: UInt32 = layers[i]!
1050			let templateId: UInt64? = templateIds[i] ?? nil
1051			if !SportvatarTemplate.isCollectibleLayerAccessory(layer: layerId, series: series){ 
1052				if templateId == nil{ 
1053					panic("Core Layer missing ".concat(layerId.toString()).concat(" - ").concat(i.toString()).concat("/").concat(layers.length.toString()))
1054				}
1055				let template = SportvatarTemplate.getTemplate(id: templateId!)!
1056				if template.series != series{ 
1057					panic("Template belonging to the wrong Series")
1058				}
1059				if template.layer != layerId{ 
1060					panic("Template belonging to the wrong Layer")
1061				}
1062				if template.name == "clothing"{ 
1063					metadata["sport"] = template.sport
1064				}
1065				let templateRarity: String = template.rarity
1066				var checkRarity: Bool = false
1067				if flameRarity == "common"{ 
1068					if templateRarity != "common"{ 
1069						checkRarity = true
1070					}
1071				} else if flameRarity == "rare"{ 
1072					if templateRarity == "epic" || templateRarity == "legendary"{ 
1073						checkRarity = true
1074					}
1075				} else if flameRarity == "epic"{ 
1076					if templateRarity == "legendary"{ 
1077						checkRarity = true
1078					}
1079				}
1080				if checkRarity{ 
1081					panic("Sport Flame does not belong to the correct Rarity")
1082				}
1083				let totalMintedComponents: UInt64 = SportvatarTemplate.getTotalMintedComponents(id: template.id)!
1084				// Makes sure that the original minting limit set for each Template has not been reached
1085				if template.maxMintableComponents > UInt64(0) && totalMintedComponents >= template.maxMintableComponents{ 
1086					panic("Reached maximum mintable count for this trait")
1087				}
1088				coreLayers[layerId] = template.id
1089				fullLayers[layerId] = template.id
1090				templates.append(template)
1091				SportvatarTemplate.increaseTotalMintedComponents(id: template.id)
1092				SportvatarTemplate.setLastComponentMintedAt(id: template.id, value: getCurrentBlock().timestamp)
1093			} else{ 
1094				fullLayers[layerId] = nil
1095			}
1096			i = i + UInt32(1)
1097		}
1098		
1099		// Generates the combination string to check for uniqueness.
1100		// This is like a barcode that defines exactly which components were used
1101		// to create the Sportvatar
1102		let combinationString = Sportvatar.getCombinationString(series: series, layers: coreLayers)
1103		
1104		// Makes sure that the combination is available and not taken already
1105		if Sportvatar.mintedCombinations.containsKey(combinationString) == true{ 
1106			panic("This combination has already been taken")
1107		}
1108		
1109		//Generate random stats based on the rarity level
1110		var minValue: UInt64 = 5
1111		var maxValue: UInt64 = 20
1112		if flameRarity == "rare"{ 
1113			minValue = 20
1114			maxValue = 30
1115		} else if flameRarity == "epic"{ 
1116			minValue = 30
1117			maxValue = 40
1118		} else if flameRarity == "legendary"{ 
1119			minValue = 40
1120			maxValue = 51
1121		}
1122		var tempRand: Int64 = 0
1123		var tempOverall: UInt64 = RandomInt(uuid: revertibleRandom<UInt64>(), field: "overall", minValue: minValue, maxValue: maxValue).getValue()
1124		var tempMax: Int64 = 0
1125		var tempMin: Int64 = 5
1126		var pointsLeft: Int64 = Int64(tempOverall)
1127		
1128		//stats["overall"] = UInt32(tempOverall)
1129		tempMax = pointsLeft - Int64(4)
1130		tempMax = tempMax > Int64(10) ? Int64(10) : tempMax
1131		tempMin = pointsLeft - Int64(40)
1132		tempMin = tempMin < Int64(1) ? Int64(1) : tempMin
1133		tempRand = tempMin == tempMax ? tempMin : Int64(RandomInt(uuid: revertibleRandom<UInt64>(), field: "mental strength", minValue: UInt64(tempMin), maxValue: UInt64(tempMax) + UInt64(1)).getValue())
1134		stats["mental strength"] = UInt32(tempRand)
1135		pointsLeft = pointsLeft - tempRand
1136		tempMax = pointsLeft - Int64(3)
1137		tempMax = tempMax > Int64(10) ? Int64(10) : tempMax
1138		tempMin = pointsLeft - Int64(30)
1139		tempMin = tempMin < Int64(1) ? Int64(1) : tempMin
1140		tempRand = tempMin == tempMax ? tempMin : Int64(RandomInt(uuid: revertibleRandom<UInt64>(), field: "speed", minValue: UInt64(tempMin), maxValue: UInt64(tempMax) + UInt64(1)).getValue())
1141		stats["speed"] = UInt32(tempRand)
1142		pointsLeft = pointsLeft - tempRand
1143		tempMax = pointsLeft - Int64(2)
1144		tempMax = tempMax > Int64(10) ? Int64(10) : tempMax
1145		tempMin = pointsLeft - Int64(20)
1146		tempMin = tempMin < Int64(1) ? Int64(1) : tempMin
1147		tempRand = tempMin == tempMax ? tempMin : Int64(RandomInt(uuid: revertibleRandom<UInt64>(), field: "power", minValue: UInt64(tempMin), maxValue: UInt64(tempMax) + UInt64(1)).getValue())
1148		stats["power"] = UInt32(tempRand)
1149		pointsLeft = pointsLeft - tempRand
1150		tempMax = pointsLeft - Int64(1)
1151		tempMax = tempMax > Int64(10) ? Int64(10) : tempMax
1152		tempMin = pointsLeft - Int64(10)
1153		tempMin = tempMin < Int64(1) ? Int64(1) : tempMin
1154		tempRand = tempMin == tempMax ? tempMin : Int64(RandomInt(uuid: revertibleRandom<UInt64>(), field: "technique", minValue: UInt64(tempMin), maxValue: UInt64(tempMax) + UInt64(1)).getValue())
1155		stats["technique"] = UInt32(tempRand)
1156		pointsLeft = pointsLeft - tempRand
1157		stats["endurance"] = UInt32(pointsLeft)
1158		if pointsLeft < Int64(1){ 
1159			panic("Error distributing stat points to Sportvatar")
1160		}
1161		let royalties: [Royalty] = []
1162		royalties.append(Royalty(wallet: self.account.capabilities.get<&FlowToken.Vault>(/public/flowTokenReceiver), cut: Sportvatar.getMarketplaceCut(), type: RoyaltyType.percentage))
1163		
1164		// Mint the new Sportvatar NFT by passing the metadata to it
1165		var newNFT <- create NFT(series: series, layers: fullLayers, metadata: metadata, stats: stats, creatorAddress: address, royalties: Royalties(royalty: royalties), rarity: flameRarity)
1166		
1167		// Adds the combination to the arrays to remember it
1168		Sportvatar.addMintedCombination(combination: combinationString)
1169		
1170		// Emits the Created event to notify about its existence
1171		emit Created(id: newNFT.id, mint: newNFT.mint, series: newNFT.series, address: address)
1172		i = UInt32(0)
1173		let sportbitLayers:{ UInt32: UInt64} ={} 
1174		while i < UInt32(sportbits.length){ 
1175			let sportbitTemp <- sportbits[i] <- nil
1176			if sportbitTemp != nil{ 
1177				let tempLayer: UInt32 = sportbitTemp?.getLayer()!
1178				if sportbitLayers[tempLayer] == nil{ 
1179					sportbitLayers[tempLayer] = sportbitTemp?.getTemplate()?.id
1180					let temp <- newNFT.setSportbit(layer: tempLayer, sportbit: <-sportbitTemp!)
1181					if temp != nil{ 
1182						panic("Sportbit already set and preventing to be destroyed")
1183					}
1184					destroy temp
1185				} else{ 
1186					destroy sportbitTemp
1187					panic("Sending multiple Sportbits for the same Layer")
1188				}
1189			} else{ 
1190				destroy sportbitTemp
1191			}
1192		}
1193		destroy sportbits
1194		destroy sportflame
1195		return <-newNFT
1196	}
1197	
1198	// These functions will return the current Royalty cuts for
1199	// both the Creator and the Marketplace.
1200	access(all)
1201	fun getRoyaltyCut(): UFix64{ 
1202		return self.royaltyCut
1203	}
1204	
1205	access(all)
1206	fun getMarketplaceCut(): UFix64{ 
1207		return self.marketplaceCut
1208	}
1209	
1210	// Only Admins will be able to call the set functions to
1211	// manage Royalties and Marketplace cuts.
1212	access(account)
1213	fun setRoyaltyCut(value: UFix64){ 
1214		self.royaltyCut = value
1215	}
1216	
1217	access(account)
1218	fun setMarketplaceCut(value: UFix64){ 
1219		self.marketplaceCut = value
1220	}
1221	
1222	// This is the main Admin resource that will allow the owner
1223	// to generate new Templates, Components and Packs
1224	access(all)
1225	resource Admin{ 
1226		
1227		//This will create a new SportvatarTemplate that
1228		// contains all the SVG and basic informations to represent
1229		// a specific part of the Sportvatar (body, hair, eyes, mouth, etc.)
1230		// More info in the SportvatarTemplate.cdc file
1231		access(all)
1232		fun createSeries(name: String, description: String, svgPrefix: String, svgSuffix: String, layers:{ UInt32: SportvatarTemplate.Layer}, colors:{ UInt32: String}, metadata:{ String: String}, maxMintable: UInt64): @SportvatarTemplate.Series{ 
1233			return <-SportvatarTemplate.createSeries(name: name, description: description, svgPrefix: svgPrefix, svgSuffix: svgSuffix, layers: layers, colors: colors, metadata: metadata, maxMintable: maxMintable)
1234		}
1235		
1236		//This will create a new SportvatarTemplate that
1237		// contains all the SVG and basic informations to represent
1238		// a specific part of the Sportvatar (body, hair, eyes, mouth, etc.)
1239		// More info in the SportvatarTemplate.cdc file
1240		access(all)
1241		fun createTemplate(name: String, description: String, series: UInt64, layer: UInt32, metadata:{ String: String}, rarity: String, sport: String, svg: String, maxMintableComponents: UInt64): @SportvatarTemplate.Template{ 
1242			return <-SportvatarTemplate.createTemplate(name: name, description: description, series: series, layer: layer, metadata: metadata, rarity: rarity, sport: sport, svg: svg, maxMintableComponents: maxMintableComponents)
1243		}
1244		
1245		//This will mint a new Component based from a selected Template
1246		access(all)
1247		fun createSportbit(templateId: UInt64): @Sportbit.NFT{ 
1248			return <-Sportbit.createSportbit(templateId: templateId)
1249		}
1250		
1251		//This will mint Components in batch and return a Collection instead of the single NFT
1252		access(all)
1253		fun batchCreateSportbits(templateId: UInt64, quantity: UInt64): @Sportbit.Collection{ 
1254			return <-Sportbit.batchCreateSportbits(templateId: templateId, quantity: quantity)
1255		}
1256		
1257		// This function will generate a new Pack containing a set of components.
1258		// A random string is passed to manage permissions for the
1259		// purchase of it (more info on SportvatarPack.cdc).
1260		// Finally the sale price is set as well.
1261		access(all)
1262		fun createPack(components: @[Sportbit.NFT], randomString: String, price: UFix64, flameCount: UInt32, series: UInt32, name: String): @SportvatarPack.Pack{ 
1263			return <-SportvatarPack.createPack(components: <-components, randomString: randomString, price: price, flameCount: flameCount, series: series, name: name)
1264		}
1265		
1266		// With this function you can generate a new Admin resource
1267		// and pass it to another user if needed
1268		access(all)
1269		fun createNewAdmin(): @Admin{ 
1270			return <-create Admin()
1271		}
1272		
1273		// Helper functions to update the Royalty cut
1274		access(all)
1275		fun setRoyaltyCut(value: UFix64){ 
1276			Sportvatar.setRoyaltyCut(value: value)
1277		}
1278		
1279		// Helper functions to update the Marketplace cut
1280		access(all)
1281		fun setMarketplaceCut(value: UFix64){ 
1282			Sportvatar.setMarketplaceCut(value: value)
1283		}
1284	}
1285	
1286	init(){ 
1287		self.CollectionPublicPath = /public/SportvatarCollection
1288		self.CollectionStoragePath = /storage/SportvatarCollection
1289		self.AdminStoragePath = /storage/SportvatarAdmin
1290		
1291		// Initialize the total supply
1292		self.totalSupply = UInt64(0)
1293		self.mintedCombinations ={} 
1294		self.mintedNames ={} 
1295		
1296		// Set the default Royalty and Marketplace cuts
1297		self.royaltyCut = 0.01
1298		self.marketplaceCut = 0.05
1299		self.account.storage.save<@{NonFungibleToken.Collection}>(<-Sportvatar.createEmptyCollection(nftType: Type<@Sportvatar.Collection>()), to: Sportvatar.CollectionStoragePath)
1300		var capability_1 = self.account.capabilities.storage.issue<&Sportvatar.Collection>(Sportvatar.CollectionStoragePath)
1301		self.account.capabilities.publish(capability_1, at: Sportvatar.CollectionPublicPath)
1302		
1303		// Put the Admin resource in storage
1304		self.account.storage.save<@Admin>(<-create Admin(), to: self.AdminStoragePath)
1305		emit ContractInitialized()
1306	}
1307}
1308