Smart Contract

TheFabricantS2ItemNFT

A.7752ea736384322f.TheFabricantS2ItemNFT

Deployed

4h ago
Feb 28, 2026, 08:14:46 PM UTC

Dependents

0 imports
1/*
2	Description: TheFabricantS2ItemNFT Contract
3   
4	TheFabricantS2ItemNFT NFTs are mintable by anyone, but requires a combination of 1 
5	TheFabricantS2GarmentNFT NFT and 1 TheFabricantS2MaterialNFT NFT.
6*/
7
8import NonFungibleToken from 0x1d7e57aa55817448
9
10import FungibleToken from 0xf233dcee88fe0abe
11
12import TheFabricantS2GarmentNFT from 0x7752ea736384322f
13
14import TheFabricantS2MaterialNFT from 0x7752ea736384322f
15
16access(all)
17contract TheFabricantS2ItemNFT: NonFungibleToken{ 
18	
19	// -----------------------------------------------------------------------
20	// TheFabricantS2ItemNFT contract Events
21	// -----------------------------------------------------------------------
22	
23	// Emitted when the Item contract is created
24	access(all)
25	event ContractInitialized()
26	
27	// Emitted when a new ItemData struct is created
28	access(all)
29	event ItemDataCreated(itemDataID: UInt32, coCreator: Address, metadatas:{ String: TheFabricantS2ItemNFT.Metadata})
30	
31	// Emitted when a mutable metadata in an itemData is changed
32	access(all)
33	event ItemMetadataChanged(itemDataID: UInt32, metadataKey: String, metadataValue: String)
34	
35	// Emitted when a mutable metadata in an itemData is set to immutable
36	access(all)
37	event ItemMetadataImmutable(itemDataID: UInt32, metadataKey: String)
38	
39	// Emitted when an Item is minted
40	access(all)
41	event ItemMinted(itemID: UInt64, itemDataID: UInt32, serialNumber: UInt32)
42	
43	// Emitted when an Item's name is changed
44	access(all)
45	event ItemNameChanged(id: UInt64, name: String)
46	
47	// Emitted when an ItemData is allocated 
48	access(all)
49	event ItemDataAllocated(garmentDataID: UInt32, materialDataID: UInt32, primaryColor: String, secondaryColor: String, key: String, itemDataID: UInt32)
50	
51	// Emitted when the items are set to be splittable
52	access(all)
53	event ItemNFTNowSplittable()
54	
55	// Emitted when the number of items with ItemDataID that can be minted changes
56	access(all)
57	event numberItemDataMintableChanged(itemDataID: UInt32, number: UInt32)
58	
59	// Emitted when an ItemData is retired
60	access(all)
61	event ItemDataIDRetired(itemDataID: UInt32)
62	
63	// Emitted when a color is added to availablePrimaryColors array
64	access(all)
65	event PrimaryColorAdded(color: String)
66	
67	// Emitted when a color is added to availableSecondaryColors array
68	access(all)
69	event SecondaryColorAdded(color: String)
70	
71	// Emitted when a color is removed from availablePrimaryColors array
72	access(all)
73	event PrimaryColorRemoved(color: String)
74	
75	// Emitted when a color is removed from availableSecondaryColors array
76	access(all)
77	event SecondaryColorRemoved(color: String)
78	
79	// Events for Collection-related actions
80	//
81	// Emitted when a Item is withdrawn from a Collection
82	access(all)
83	event Withdraw(id: UInt64, from: Address?)
84	
85	// Emitted when a Item is deposited into a Collection
86	access(all)
87	event Deposit(id: UInt64, to: Address?)
88	
89	// Emitted when a Item is destroyed
90	access(all)
91	event ItemDestroyed(id: UInt64)
92	
93	// -----------------------------------------------------------------------
94	// contract-level fields.	  
95	// These contain actual values that are stored in the smart contract.
96	// -----------------------------------------------------------------------
97	access(all)
98	let CollectionStoragePath: StoragePath
99	
100	access(all)
101	let CollectionPublicPath: PublicPath
102	
103	access(all)
104	let AdminStoragePath: StoragePath
105	
106	// itemDataID: number of NFTs with that ItemDataID are minted
107	access(self)
108	var numberMintedPerItem:{ UInt32: UInt32}
109	
110	// itemDataID: how many items with itemData can be minted
111	access(self)
112	var numberMintablePerItemData:{ UInt32: UInt32}
113	
114	// itemDataID: itemData struct
115	access(self)
116	var itemDatas:{ UInt32: ItemData}
117	
118	// concat of garmentDataID_materialDataID_primaryColor_secondaryColor: itemDataID (eg. 1_1_FFFFFF_000000)
119	access(self)
120	var itemDataAllocation:{ String: UInt32}
121	
122	// itemDataID: whether item with ItemDataID cannot be minted anymore
123	access(self)
124	var isItemDataRetired:{ UInt32: Bool}
125	
126	// Dictionary of the nft with id and its current owner address
127	access(self)
128	var nftIDToOwner:{ UInt64: Address}
129	
130	// array of available primaryColors
131	access(self)
132	var availablePrimaryColors: [String]
133	
134	// array of available secondaryColors
135	access(self)
136	var availableSecondaryColors: [String]
137	
138	// Keeps track of how many unique ItemDatas are created
139	access(all)
140	var nextItemDataID: UInt32
141	
142	// Keeps track of how many unique ItemDataAllocations are created
143	access(all)
144	var nextItemDataAllocation: UInt32
145	
146	// Are garment and material removable from item
147	access(all)
148	var isSplittable: Bool
149	
150	access(all)
151	var totalSupply: UInt64
152	
153	// metadata of an ItemData struct that contains the metadata value
154	// and whether it is mutable
155	access(all)
156	struct Metadata{ 
157		access(all)
158		var metadataValue: String
159		
160		access(all)
161		var mutable: Bool
162		
163		init(metadataValue: String, mutable: Bool){ 
164			self.metadataValue = metadataValue
165			self.mutable = mutable
166		}
167		
168		access(all)
169		fun setMetadataImmutable(){ 
170			pre{ 
171				self.mutable == true:
172					"metadata is already immutable"
173			}
174			self.mutable = false
175		}
176		
177		access(all)
178		fun setMetadataValue(metadataValue: String){ 
179			pre{ 
180				self.mutable == true:
181					"metadata is already immutable"
182			}
183			self.metadataValue = metadataValue
184		}
185	}
186	
187	access(all)
188	struct ItemData{ 
189		
190		// The unique ID for the Item Data
191		access(all)
192		let itemDataID: UInt32
193		
194		// stores link to image
195		// the address of the user who created the unique combination
196		access(all)
197		let coCreator: Address
198		
199		// other metadata
200		access(self)
201		let metadatas:{ String: TheFabricantS2ItemNFT.Metadata}
202		
203		init(coCreator: Address, metadatas:{ String: TheFabricantS2ItemNFT.Metadata}){ 
204			self.itemDataID = TheFabricantS2ItemNFT.nextItemDataID
205			self.coCreator = coCreator
206			self.metadatas = metadatas
207			TheFabricantS2ItemNFT.isItemDataRetired[self.itemDataID] = false
208			
209			// set default number mintable of itemData to 1
210			TheFabricantS2ItemNFT.numberMintablePerItemData[self.itemDataID] = 1
211			
212			// Increment the ID so that it isn't used again
213			TheFabricantS2ItemNFT.nextItemDataID = TheFabricantS2ItemNFT.nextItemDataID + 1 as UInt32
214			emit ItemDataCreated(itemDataID: self.itemDataID, coCreator: self.coCreator, metadatas: self.metadatas)
215		}
216		
217		// change a mutable metadata in the metadata struct
218		access(all)
219		fun setMetadata(metadataKey: String, metadataValue: String){ 
220			(self.metadatas[metadataKey]!).setMetadataValue(metadataValue: metadataValue)
221			emit ItemMetadataChanged(itemDataID: self.itemDataID, metadataKey: metadataKey, metadataValue: metadataValue)
222		}
223		
224		// prevent changing of a metadata in the metadata struct
225		access(all)
226		fun setMetadataKeyImmutable(metadataKey: String){ 
227			(self.metadatas[metadataKey]!).setMetadataImmutable()
228			emit ItemMetadataImmutable(itemDataID: self.itemDataID, metadataKey: metadataKey)
229		}
230		
231		access(all)
232		fun getMetadata():{ String: TheFabricantS2ItemNFT.Metadata}{ 
233			return self.metadatas
234		}
235	}
236	
237	access(all)
238	struct Item{ 
239		
240		// The ID of the itemData that the item references
241		access(all)
242		let itemDataID: UInt32
243		
244		// The N'th NFT with 'ItemDataID' minted
245		access(all)
246		let serialNumber: UInt32
247		
248		init(itemDataID: UInt32){ 
249			pre{ 
250				Int(TheFabricantS2ItemNFT.numberMintedPerItem[itemDataID]!) < Int(TheFabricantS2ItemNFT.numberMintablePerItemData[itemDataID]!):
251					"maximum number of TheFabricantS2ItemNFT with itemDataID reached"
252			}
253			self.itemDataID = itemDataID
254			
255			// Increment the ID so that it isn't used again
256			TheFabricantS2ItemNFT.numberMintedPerItem[itemDataID] = TheFabricantS2ItemNFT.numberMintedPerItem[itemDataID]! + 1 as UInt32
257			self.serialNumber = TheFabricantS2ItemNFT.numberMintedPerItem[itemDataID]!
258		}
259	}
260	
261	// Royalty struct that each TheFabricantS2ItemNFT will contain
262	access(all)
263	struct Royalty{ 
264		access(all)
265		let wallet: Capability<&{FungibleToken.Receiver}>
266		
267		access(all)
268		let initialCut: UFix64
269		
270		access(all)
271		let cut: UFix64
272		
273		/// @param wallet : The wallet to send royalty too
274		init(wallet: Capability<&{FungibleToken.Receiver}>, initialCut: UFix64, cut: UFix64){ 
275			self.wallet = wallet
276			self.initialCut = initialCut
277			self.cut = cut
278		}
279	}
280	
281	// The resource that represents the Item NFTs
282	//
283	access(all)
284	resource NFT: NonFungibleToken.NFT{ 
285		
286		// Global unique Item ID
287		access(all)
288		let id: UInt64
289		
290		// struct of Item
291		access(all)
292		let item: Item
293		
294		// name of nft, can be changed
295		access(all)
296		var name: String
297		
298		// Royalty struct
299		access(all)
300		let royaltyVault: TheFabricantS2ItemNFT.Royalty
301		
302		// after you remove the garment and material from the item, the TheFabricantS2ItemNFT will be considered "dead". 
303		// accounts will be unable to deposit, withdraw or call functions of the nft.
304		access(all)
305		var isDead: Bool
306		
307		// this is where the garment nft is stored, it cannot be moved out
308		access(self)
309		var garment: @TheFabricantS2GarmentNFT.NFT?
310		
311		// this is where the material nft is stored, it cannot be moved out
312		access(self)
313		var material: @TheFabricantS2MaterialNFT.NFT?
314		
315		init(serialNumber: UInt32, name: String, itemDataID: UInt32, royaltyVault: TheFabricantS2ItemNFT.Royalty, garment: @TheFabricantS2GarmentNFT.NFT, material: @TheFabricantS2MaterialNFT.NFT){ 
316			TheFabricantS2ItemNFT.totalSupply = TheFabricantS2ItemNFT.totalSupply + 1 as UInt64
317			self.id = TheFabricantS2ItemNFT.totalSupply
318			self.name = name
319			self.royaltyVault = royaltyVault
320			self.isDead = false
321			self.garment <- garment
322			self.material <- material
323			self.item = Item(itemDataID: itemDataID)
324			
325			// Emitted when a Item is minted
326			emit ItemMinted(itemID: self.id, itemDataID: itemDataID, serialNumber: serialNumber)
327		}
328		
329		//Make Item considered dead. Deposit garment and material to respective vaults
330		access(contract)
331		fun split(garmentCap: Capability<&{TheFabricantS2GarmentNFT.GarmentCollectionPublic}>, materialCap: Capability<&{TheFabricantS2MaterialNFT.MaterialCollectionPublic}>){ 
332			pre{ 
333				!self.isDead:
334					"Cannot split. Item is dead"
335				TheFabricantS2ItemNFT.isSplittable:
336					"Item is set to unsplittable"
337				garmentCap.check():
338					"Garment Capability is invalid"
339				materialCap.check():
340					"Material Capability is invalid"
341			}
342			let garmentOptional <- self.garment <- nil
343			let materialOptional <- self.material <- nil
344			let garmentRecipient = garmentCap.borrow()!
345			let materialRecipient = materialCap.borrow()!
346			let garment <- garmentOptional!
347			let material <- materialOptional!
348			let garmentNFT <- garment as! @{NonFungibleToken.NFT}
349			let materialNFT <- material as! @{NonFungibleToken.NFT}
350			garmentRecipient.deposit(token: <-garmentNFT)
351			materialRecipient.deposit(token: <-materialNFT)
352			TheFabricantS2ItemNFT.numberMintedPerItem[self.item.itemDataID] = TheFabricantS2ItemNFT.numberMintedPerItem[self.item.itemDataID]! - 1 as UInt32
353			self.isDead = true
354		}
355		
356		// get a reference to the garment that item stores
357		access(all)
358		fun borrowGarment(): &TheFabricantS2GarmentNFT.NFT? { 
359		    return &self.garment as &TheFabricantS2GarmentNFT.NFT?
360		}
361		
362		// get a reference to the material that item stores
363		access(all)
364		fun borrowMaterial(): &TheFabricantS2MaterialNFT.NFT?{ 
365			return &self.material as &TheFabricantS2MaterialNFT.NFT?
366		}
367		
368		access(all)
369		fun createEmptyCollection(): @{NonFungibleToken.Collection}{ 
370			return <-create Collection()
371		}
372
373		access(all)
374		view fun getViews(): [Type]{ 
375			return []
376		}
377		
378		access(all)
379		fun resolveView(_ view: Type): AnyStruct?{ 
380			return nil
381		}
382	}
383	
384	//destroy item if it is considered dead
385	access(all)
386	fun cleanDeadItems(item: @TheFabricantS2ItemNFT.NFT){ 
387		pre{ 
388			item.isDead:
389				"Cannot destroy, item not dead"
390		}
391		destroy item
392	}
393	
394	// mint the NFT, based on a combination of garment, material, primaryColor and secondaryColor. 
395	// The itemData that is used to mint the Item is based on the garment and material' garmentDataID and materialDataID
396	access(all)
397	fun mintNFT(name: String, royaltyVault: TheFabricantS2ItemNFT.Royalty, garment: @TheFabricantS2GarmentNFT.NFT, material: @TheFabricantS2MaterialNFT.NFT, primaryColor: String, secondaryColor: String): @NFT{ 
398		let garmentDataID = garment.garment.garmentDataID
399		let materialDataID = material.material.materialDataID
400		let key = TheFabricantS2ItemNFT.getUniqueString(garmentDataID: garmentDataID, materialDataID: materialDataID, primaryColor: primaryColor, secondaryColor: secondaryColor)
401		
402		//check whether unique combination is allocated
403		let itemDataID = TheFabricantS2ItemNFT.itemDataAllocation[key] ?? panic("Cannot mint Item. ItemData not found")
404		
405		//check whether itemdata is retired
406		if TheFabricantS2ItemNFT.isItemDataRetired[itemDataID]!{ 
407			panic("Cannot mint Item. ItemDataID retired")
408		}
409		let numInItem = TheFabricantS2ItemNFT.numberMintedPerItem[itemDataID] ?? panic("Maximum number of Items with itemDataID minted")
410		let item <- create NFT(serialNumber: numInItem + 1, name: name, itemDataID: itemDataID, royaltyVault: royaltyVault, garment: <-garment, material: <-material)
411		return <-item
412	}
413	
414	// This is the interface that users can cast their Item Collection as
415	// to allow others to deposit Items into their Collection. It also allows for reading
416	// the IDs of Items in the Collection.
417	access(all)
418	resource interface ItemCollectionPublic{ 
419		access(all)
420		fun deposit(token: @{NonFungibleToken.NFT})
421		
422		access(all)
423		fun batchDeposit(tokens: @{NonFungibleToken.Collection})
424		
425		access(all)
426		fun getIDs(): [UInt64]
427		
428		access(all)
429		view fun borrowNFT(_ id: UInt64): &{NonFungibleToken.NFT}?
430		
431		access(all)
432		fun borrowItem(id: UInt64): &TheFabricantS2ItemNFT.NFT?{ 
433			// If the result isn't nil, the id of the returned reference
434			// should be the same as the argument to the function
435			post{ 
436				result == nil || result?.id == id:
437					"Cannot borrow Item reference: The ID of the returned reference is incorrect"
438			}
439		}
440	}
441	
442	// Collection is a resource that every user who owns NFTs 
443	// will store in their account to manage their NFTS
444	//
445	access(all)
446	resource Collection: ItemCollectionPublic, NonFungibleToken.Provider, NonFungibleToken.Receiver, NonFungibleToken.Collection, NonFungibleToken.CollectionPublic{ 
447		// Dictionary of Item conforming tokens
448		// NFT is a resource type with a UInt64 ID field
449		access(all)
450		var ownedNFTs: @{UInt64:{ NonFungibleToken.NFT}}
451		
452		init(){ 
453			self.ownedNFTs <-{} 
454		}
455		
456		access(all)
457		fun split(id: UInt64, garmentCap: Capability<&{TheFabricantS2GarmentNFT.GarmentCollectionPublic}>, materialCap: Capability<&{TheFabricantS2MaterialNFT.MaterialCollectionPublic}>){ 
458			let token <- self.ownedNFTs.remove(key: id) ?? panic("Cannot withdraw: Item does not exist in the collection")
459			let item <- token as! @TheFabricantS2ItemNFT.NFT
460			item.split(garmentCap: garmentCap, materialCap: materialCap)
461			self.ownedNFTs[id] <-! item
462		}
463		
464		// withdraw removes an Item from the Collection and moves it to the caller
465		//
466		// Parameters: withdrawID: The ID of the NFT 
467		// that is to be removed from the Collection
468		//
469		// returns: @NonFungibleToken.NFT the token that was withdrawn
470		access(NonFungibleToken.Withdraw)
471		fun withdraw(withdrawID: UInt64): @{NonFungibleToken.NFT}{ 
472			// Remove the nft from the Collection
473			let token <- self.ownedNFTs.remove(key: withdrawID) ?? panic("Cannot withdraw: Item does not exist in the collection")
474			emit Withdraw(id: token.id, from: self.owner?.address)
475			
476			// Return the withdrawn token
477			return <-token
478		}
479		
480		// batchWithdraw withdraws multiple tokens and returns them as a Collection
481		//
482		// Parameters: ids: An array of IDs to withdraw
483		//
484		// Returns: @NonFungibleToken.Collection: A collection that contains
485		//										the withdrawn Items
486		//
487		access(all)
488		fun batchWithdraw(ids: [UInt64]): @{NonFungibleToken.Collection}{ 
489			// Create a new empty Collection
490			var batchCollection <- create Collection()
491			
492			// Iterate through the ids and withdraw them from the Collection
493			for id in ids{ 
494				batchCollection.deposit(token: <-self.withdraw(withdrawID: id))
495			}
496			
497			// Return the withdrawn tokens
498			return <-batchCollection
499		}
500		
501		// deposit takes a Item and adds it to the Collections dictionary
502		//
503		// Paramters: token: the NFT to be deposited in the collection
504		//
505		access(all)
506		fun deposit(token: @{NonFungibleToken.NFT}){ 
507			//todo: someFunction that transfers royalty
508			// Cast the deposited token as  NFT to make sure
509			// it is the correct type
510			let token <- token as! @TheFabricantS2ItemNFT.NFT
511			
512			// Get the token's ID
513			let id = token.id
514			
515			// Add the new token to the dictionary
516			let oldToken <- self.ownedNFTs[id] <- token
517			
518			// Set the global mapping of nft id to new owner
519			TheFabricantS2ItemNFT.nftIDToOwner[id] = self.owner?.address
520			
521			// Only emit a deposit event if the Collection 
522			// is in an account's storage
523			if self.owner?.address != nil{ 
524				emit Deposit(id: id, to: self.owner?.address)
525			}
526			
527			// Destroy the empty old token that was "removed"
528			destroy oldToken
529		}
530		
531		// batchDeposit takes a Collection object as an argument
532		// and deposits each contained NFT into this Collection
533		access(all)
534		fun batchDeposit(tokens: @{NonFungibleToken.Collection}){ 
535			// Get an array of the IDs to be deposited
536			let keys = tokens.getIDs()
537			
538			// Iterate through the keys in the collection and deposit each one
539			for key in keys{ 
540				self.deposit(token: <-tokens.withdraw(withdrawID: key))
541			}
542			
543			// Destroy the empty Collection
544			destroy tokens
545		}
546		
547		// getIDs returns an array of the IDs that are in the Collection
548		access(all)
549		view fun getIDs(): [UInt64]{ 
550			return self.ownedNFTs.keys
551		}
552		
553		// borrowNFT Returns a borrowed reference to a Item in the Collection
554		// so that the caller can read its ID
555		//
556		// Parameters: id: The ID of the NFT to get the reference for
557		//
558		// Returns: A reference to the NFT
559		//
560		// Note: This only allows the caller to read the ID of the NFT,
561		// not an specific data. Please use borrowItem to 
562		// read Item data.
563		//
564		access(all)
565		view fun borrowNFT(_ id: UInt64): &{NonFungibleToken.NFT}?{ 
566			return (&self.ownedNFTs[id] as &{NonFungibleToken.NFT}?)!
567		}
568		
569		// Parameters: id: The ID of the NFT to get the reference for
570		//
571		// Returns: A reference to the NFT
572		access(all)
573		fun borrowItem(id: UInt64): &TheFabricantS2ItemNFT.NFT?{ 
574			if self.ownedNFTs[id] != nil{ 
575				let ref = (&self.ownedNFTs[id] as &{NonFungibleToken.NFT}?)!
576				return ref as! &TheFabricantS2ItemNFT.NFT
577			} else{ 
578				return nil
579			}
580		}
581		
582		access(all)
583		view fun getSupportedNFTTypes():{ Type: Bool}{ 
584			panic("implement me")
585		}
586		
587		access(all)
588		view fun isSupportedNFTType(type: Type): Bool{ 
589			panic("implement me")
590		}
591		
592		access(all)
593		fun createEmptyCollection(): @{NonFungibleToken.Collection}{ 
594			return <-create Collection()
595		}
596	
597	// If a transaction destroys the Collection object,
598	// All the NFTs contained within are also destroyed!
599	//
600	}
601	
602	// Admin is a special authorization resource that 
603	// allows the owner to perform important functions to modify the 
604	// various aspects of the Items and NFTs
605	//
606	access(all)
607	resource Admin{ 
608		
609		// create itemdataid allocation based on the 
610		// garmentDataID, materialDataID, primaryColor and secondaryColor
611		// and create an itemdata struct based on it
612		access(all)
613		fun createItemDataWithAllocation(garmentDataID: UInt32, materialDataID: UInt32, primaryColor: String, secondaryColor: String, metadatas:{ String: TheFabricantS2ItemNFT.Metadata}, coCreator: Address): UInt32{ 
614			
615			// check whether colors are valid colors
616			let pCAvailable = TheFabricantS2ItemNFT.availablePrimaryColors.contains(primaryColor)
617			let pSCAvailable = TheFabricantS2ItemNFT.availableSecondaryColors.contains(secondaryColor)
618			let garmentDataPresent = TheFabricantS2GarmentNFT.getGarmentDatas().containsKey(garmentDataID)
619			let materialDataPresent = TheFabricantS2MaterialNFT.getMaterialDatas().containsKey(materialDataID)
620			assert(pCAvailable, message: "PrimaryColor not available")
621			assert(pSCAvailable, message: "SecondaryColor not available")
622			assert(garmentDataPresent, message: "GarmentData not found")
623			assert(materialDataPresent, message: "MaterialData not found")
624
625			// set the primaryColor and secondaryColor metadata of Metadata struct
626			metadatas["primaryColor"] = TheFabricantS2ItemNFT.Metadata(metadataValue: primaryColor, mutable: false)
627			metadatas["secondaryColor"] = TheFabricantS2ItemNFT.Metadata(metadataValue: secondaryColor, mutable: false)
628			
629			// check whether unique combination is allocated already
630			let key = TheFabricantS2ItemNFT.getUniqueString(garmentDataID: garmentDataID, materialDataID: materialDataID, primaryColor: primaryColor, secondaryColor: secondaryColor)
631			if TheFabricantS2ItemNFT.itemDataAllocation.containsKey(key){ 
632				panic("Item already allocated")
633			}
634			
635			// set unique combination's itemdataallocation, then increment nextItemDataAllocation
636			TheFabricantS2ItemNFT.itemDataAllocation[key] = TheFabricantS2ItemNFT.nextItemDataAllocation
637			emit ItemDataAllocated(garmentDataID: garmentDataID, materialDataID: materialDataID, primaryColor: primaryColor, secondaryColor: secondaryColor, key: key, itemDataID: TheFabricantS2ItemNFT.nextItemDataAllocation)
638			TheFabricantS2ItemNFT.nextItemDataAllocation = TheFabricantS2ItemNFT.nextItemDataAllocation + 1 as UInt32
639			
640			// create new itemData 
641			var newItem = ItemData(coCreator: coCreator, metadatas: metadatas)
642			
643			// Store it in the contract storage
644			let newID = newItem.itemDataID
645			TheFabricantS2ItemNFT.itemDatas[newID] = newItem
646			TheFabricantS2ItemNFT.numberMintedPerItem[newID] = 0 as UInt32
647			return newID
648		}
649		
650		// change the metadatavalue of an itemData
651		access(all)
652		fun setMetadata(itemDataID: UInt32, metadataKey: String, metadataValue: String){ 
653			let itemDataTemp = TheFabricantS2ItemNFT.itemDatas[itemDataID]!
654			itemDataTemp.setMetadata(metadataKey: metadataKey, metadataValue: metadataValue)
655			TheFabricantS2ItemNFT.itemDatas[itemDataID] = itemDataTemp
656		}
657		
658		// make the metadatavalue of an itemData immutable
659		access(all)
660		fun setMetadataImmutable(itemData: UInt32, metadataKey: String){ 
661			let itemDataTemp = TheFabricantS2ItemNFT.itemDatas[itemData]!
662			itemDataTemp.setMetadataKeyImmutable(metadataKey: metadataKey)
663			TheFabricantS2ItemNFT.itemDatas[itemData] = itemDataTemp
664		}
665		
666		// add the primaryColor to array of availablePrimaryColors
667		access(all)
668		fun addPrimaryColor(color: String){ 
669			pre{ 
670				!TheFabricantS2ItemNFT.availablePrimaryColors.contains(color):
671					"availablePrimaryColors already has color"
672			}
673			TheFabricantS2ItemNFT.availablePrimaryColors.append(color)
674			emit PrimaryColorAdded(color: color)
675		}
676		
677		// add the primaryColor to array of availablePrimaryColors
678		access(all)
679		fun addSecondaryColor(color: String){ 
680			pre{ 
681				!TheFabricantS2ItemNFT.availableSecondaryColors.contains(color):
682					"availableSecondaryColors does not contain color"
683			}
684			TheFabricantS2ItemNFT.availableSecondaryColors.append(color)
685			emit SecondaryColorAdded(color: color)
686		}
687		
688		// add the primaryColor to array of availablePrimaryColors
689		access(all)
690		fun removePrimaryColor(color: String){ 
691			pre{ 
692				TheFabricantS2ItemNFT.availablePrimaryColors.contains(color):
693					"availablePrimaryColors does not contain color"
694			}
695			var index = 0
696			for primaryColor in TheFabricantS2ItemNFT.availablePrimaryColors{ 
697				if primaryColor == color{ 
698					TheFabricantS2ItemNFT.availablePrimaryColors.remove(at: index)
699				} else{ 
700					index = index + 1
701				}
702			}
703			emit PrimaryColorRemoved(color: color)
704		}
705		
706		// add the primaryColor to array of availablePrimaryColors
707		access(all)
708		fun removeSecondaryColor(color: String){ 
709			pre{ 
710				TheFabricantS2ItemNFT.availableSecondaryColors.contains(color):
711					"availableSecondaryColors already has color"
712			}
713			var index = 0
714			for secondaryColor in TheFabricantS2ItemNFT.availableSecondaryColors{ 
715				if secondaryColor == color{ 
716					TheFabricantS2ItemNFT.availableSecondaryColors.remove(at: index)
717				} else{ 
718					index = index + 1
719				}
720			}
721			emit SecondaryColorRemoved(color: color)
722		}
723		
724		// createNewAdmin creates a new Admin resource
725		//
726		access(all)
727		fun createNewAdmin(): @Admin{ 
728			return <-create Admin()
729		}
730		
731		// Change the royalty percentage of the contract
732		access(all)
733		fun makeSplittable(){ 
734			TheFabricantS2ItemNFT.isSplittable = true
735			emit ItemNFTNowSplittable()
736		}
737		
738		// Change the number of itemdata mintable
739		access(all)
740		fun changeItemDataNumberMintable(itemDataID: UInt32, number: UInt32){ 
741			TheFabricantS2ItemNFT.numberMintablePerItemData[itemDataID] = number
742			emit numberItemDataMintableChanged(itemDataID: itemDataID, number: number)
743		}
744		
745		// Retire itemData so that it cannot be used to mint anymore
746		access(all)
747		fun retireItemData(itemDataID: UInt32){ 
748			pre{ 
749				TheFabricantS2ItemNFT.isItemDataRetired[itemDataID] != nil:
750					"Cannot retire item: Item doesn't exist!"
751			}
752			if !TheFabricantS2ItemNFT.isItemDataRetired[itemDataID]!{ 
753				TheFabricantS2ItemNFT.isItemDataRetired[itemDataID] = true
754				emit ItemDataIDRetired(itemDataID: itemDataID)
755			}
756		}
757	}
758	
759	// -----------------------------------------------------------------------
760	// Item contract-level function definitions
761	// -----------------------------------------------------------------------
762	// createEmptyCollection creates a new, empty Collection object so that
763	// a user can store it in their account storage.
764	// Once they have a Collection in their storage, they are able to receive
765	// Items in transactions.
766	//
767	access(all)
768	fun createEmptyCollection(nftType: Type): @{NonFungibleToken.Collection}{ 
769		return <-create TheFabricantS2ItemNFT.Collection()
770	}
771	
772	// get dictionary of numberMintedPerItem
773	access(all)
774	fun getNumberMintedPerItem():{ UInt32: UInt32}{ 
775		return TheFabricantS2ItemNFT.numberMintedPerItem
776	}
777	
778	// get how many Items with itemDataID are minted 
779	access(all)
780	fun getItemNumberMinted(id: UInt32): UInt32{ 
781		let numberMinted = TheFabricantS2ItemNFT.numberMintedPerItem[id] ?? panic("itemDataID not found")
782		return numberMinted
783	}
784	
785	// get the ItemData of a specific id
786	access(all)
787	fun getItemData(id: UInt32): ItemData{ 
788		let itemData = TheFabricantS2ItemNFT.itemDatas[id] ?? panic("itemDataID not found")
789		return itemData
790	}
791	
792	// get the map of item data allocations
793	access(all)
794	fun getItemDataAllocations():{ String: UInt32}{ 
795		let itemDataAllocation = TheFabricantS2ItemNFT.itemDataAllocation
796		return itemDataAllocation
797	}
798	
799	// get the itemData allocation from the garment and material dataID
800	access(all)
801	fun getItemDataAllocation(garmentDataID: UInt32, materialDataID: UInt32, primaryColor: String, secondaryColor: String): UInt32{ 
802		let itemDataAllocation = TheFabricantS2ItemNFT.itemDataAllocation[TheFabricantS2ItemNFT.getUniqueString(garmentDataID: garmentDataID, materialDataID: materialDataID, primaryColor: primaryColor, secondaryColor: secondaryColor)] ?? panic("garment and material dataID pair not allocated")
803		return itemDataAllocation
804	}
805	
806	// get all ItemDatas created
807	access(all)
808	fun getItemDatas():{ UInt32: ItemData}{ 
809		return TheFabricantS2ItemNFT.itemDatas
810	}
811	
812	access(all)
813	fun getAvailablePrimaryColors(): [String]{ 
814		return TheFabricantS2ItemNFT.availablePrimaryColors
815	}
816	
817	access(all)
818	fun getAvailableSecondaryColors(): [String]{ 
819		return TheFabricantS2ItemNFT.availableSecondaryColors
820	}
821	
822	// get dictionary of itemdataids and whether they are retired
823	access(all)
824	fun getItemDatasRetired():{ UInt32: Bool}{ 
825		return TheFabricantS2ItemNFT.isItemDataRetired
826	}
827	
828	// get bool of if itemdataid is retired
829	access(all)
830	fun getItemDataRetired(itemDataID: UInt32): Bool?{ 
831		return TheFabricantS2ItemNFT.isItemDataRetired[itemDataID]!
832	}
833	
834	access(all)
835	fun getUniqueString(garmentDataID: UInt32, materialDataID: UInt32, primaryColor: String, secondaryColor: String): String{ 
836		return garmentDataID.toString().concat("_").concat(materialDataID.toString()).concat("_").concat(primaryColor).concat("_").concat(secondaryColor)
837	}
838	
839	access(all)
840	fun getNumberMintablePerItemData():{ UInt32: UInt32}{ 
841		return TheFabricantS2ItemNFT.numberMintablePerItemData
842	}
843	
844	access(all)
845	fun getNftIdToOwner():{ UInt64: Address}{ 
846		return TheFabricantS2ItemNFT.nftIDToOwner
847	}
848
849	access(all)
850	view fun getContractViews(resourceType: Type?): [Type]{ 
851		return []
852	}
853
854	access(all)
855	view fun resolveContractView(resourceType: Type?, viewType: Type): AnyStruct?{ 
856		return nil
857	}
858	
859	// -----------------------------------------------------------------------
860	// initialization function
861	// -----------------------------------------------------------------------
862	//
863	init(){ 
864		self.itemDatas ={} 
865		self.itemDataAllocation ={} 
866		self.numberMintedPerItem ={} 
867		self.numberMintablePerItemData ={} 
868		self.nextItemDataID = 1
869		self.nextItemDataAllocation = 1
870		self.isSplittable = false
871		self.isItemDataRetired ={} 
872		self.nftIDToOwner ={} 
873		self.totalSupply = 0
874		self.availablePrimaryColors = []
875		self.availableSecondaryColors = []
876		self.CollectionPublicPath = /public/S2ItemCollection0028
877		self.CollectionStoragePath = /storage/S2ItemCollection0028
878		self.AdminStoragePath = /storage/S2ItemAdmin0028
879		
880		// Put a new Collection in storage
881		self.account.storage.save<@Collection>(<-create Collection(), to: self.CollectionStoragePath)
882		
883		// Create a public capability for the Collection
884		var capability_1 = self.account.capabilities.storage.issue<&{ItemCollectionPublic}>(self.CollectionStoragePath)
885		self.account.capabilities.publish(capability_1, at: self.CollectionPublicPath)
886		
887		// Put the Minter in storage
888		self.account.storage.save<@Admin>(<-create Admin(), to: self.AdminStoragePath)
889		emit ContractInitialized()
890	}
891}
892