Smart Contract

MFLPackTemplate

A.8ebcbfd516b1da27.MFLPackTemplate

Deployed

1w ago
Feb 19, 2026, 09:40:23 PM UTC

Dependents

5 imports
1/**
2  This contract allows MFL to create and manage packTemplates.
3  A packTemplate is in a way the skeleton of a pack, where, among other things,
4  a max supply and  current supply are defined,
5  and whether or not packs linked to a packTemplate can be opened.
6**/
7
8access(all)
9contract MFLPackTemplate {
10
11	// Entitlements
12	access(all)
13	entitlement PackTemplateAdminAction
14
15	// Events
16	access(all)
17	event ContractInitialized()
18
19	access(all)
20	event Minted(id: UInt64)
21
22	access(all)
23	event AllowToOpenPacks(id: UInt64)
24
25	// Named Paths
26	access(all)
27	let PackTemplateAdminStoragePath: StoragePath
28
29	access(all)
30	var nextPackTemplateID: UInt64
31
32	// All packTemplates  are stored in this dictionary
33	access(self)
34	let packTemplates: @{UInt64: PackTemplate}
35
36	access(all)
37	struct PackTemplateData {
38		access(all)
39		let id: UInt64
40
41		access(all)
42		let name: String
43
44		access(all)
45		let description: String?
46
47		access(all)
48		let maxSupply: UInt32
49
50		access(all)
51		let currentSupply: UInt32
52
53		access(all)
54		let isOpenable: Bool
55
56		access(all)
57		let imageUrl: String
58
59		access(all)
60		let type: String
61
62		access(contract)
63		let slots: [Slot]
64
65		init(
66			id: UInt64,
67			name: String,
68			description: String?,
69			maxSupply: UInt32,
70			currentSupply: UInt32,
71			isOpenable: Bool,
72			imageUrl: String,
73			type: String,
74			slots: [Slot]
75		) {
76			self.id = id
77			self.name = name
78			self.description = description
79			self.maxSupply = maxSupply
80			self.currentSupply = currentSupply
81			self.isOpenable = isOpenable
82			self.imageUrl = imageUrl
83			self.type = type
84			self.slots = slots
85		}
86	}
87
88	access(all)
89	struct Slot {
90		access(all)
91		let type: String
92
93		access(contract)
94		let chances: {String: String}
95
96		access(all)
97		let count: UInt32
98
99		init(type: String, chances: {String: String}, count: UInt32) {
100			self.type = type
101			self.chances = chances
102			self.count = count
103		}
104	}
105
106	access(all)
107	resource PackTemplate {
108		access(all)
109		let id: UInt64
110
111		access(contract)
112		let name: String
113
114		access(contract)
115		let description: String?
116
117		access(contract)
118		var maxSupply: UInt32
119
120		access(contract)
121		var currentSupply: UInt32
122
123		access(contract)
124		var isOpenable: Bool
125
126		access(contract)
127		var imageUrl: String
128
129		access(contract)
130		let type: String
131
132		access(contract)
133		let slots: [Slot]
134
135		init(
136			name: String,
137			description: String?,
138			maxSupply: UInt32,
139			imageUrl: String,
140			type: String,
141			slots: [Slot]
142		) {
143			self.id = MFLPackTemplate.nextPackTemplateID
144			MFLPackTemplate.nextPackTemplateID = MFLPackTemplate.nextPackTemplateID + 1 as UInt64
145			self.name = name
146			self.description = description
147			self.maxSupply = maxSupply
148			self.currentSupply = 0
149			self.isOpenable = false
150			self.imageUrl = imageUrl
151			self.type = type
152			self.slots = slots
153			emit Minted(id: self.id)
154		}
155
156		// Enable accounts to open their packs
157		access(contract)
158		fun allowToOpenPacks() {
159			self.isOpenable = true
160		}
161
162		// Change max supply
163		access(contract)
164		fun updateMaxSupply(maxSupply: UInt32) {
165			assert(maxSupply >= self.currentSupply, message: "Current supply is greater than new max supply")
166
167			self.maxSupply = maxSupply
168		}
169
170		// Increase current supply
171		access(contract)
172		fun increaseCurrentSupply(nbToMint: UInt32) {
173			pre {
174				nbToMint <= self.maxSupply - self.currentSupply:
175					"Supply exceeded"
176			}
177			self.currentSupply = self.currentSupply + nbToMint
178		}
179	}
180
181	// Get all packTemplates IDs
182	access(all)
183	view fun getPackTemplatesIDs(): [UInt64] {
184		return self.packTemplates.keys
185	}
186
187	// Get a data reprensation of a specific packTemplate
188	access(all)
189	fun getPackTemplate(id: UInt64): PackTemplateData? {
190		if let packTemplate = self.getPackTemplateRef(id: id) {
191			let dereferenceSlot = fun (_ slot: Slot): Slot {
192				return slot
193			}
194			return PackTemplateData(
195				id: packTemplate.id,
196				name: packTemplate.name,
197				description: packTemplate.description,
198				maxSupply: packTemplate.maxSupply,
199				currentSupply: packTemplate.currentSupply,
200				isOpenable: packTemplate.isOpenable,
201				imageUrl: packTemplate.imageUrl,
202				type: packTemplate.type,
203				slots: packTemplate.slots.map(dereferenceSlot)
204			)
205		}
206		return nil
207	}
208
209	// Get a data reprensation of all packTemplates
210	access(all)
211	fun getPackTemplates(): [PackTemplateData] {
212		var packTemplatesData: [PackTemplateData] = []
213		for id in self.getPackTemplatesIDs() {
214			if let packTemplate = self.getPackTemplate(id: id) {
215				packTemplatesData.append(packTemplate)
216			}
217		}
218		return packTemplatesData
219	}
220
221	// Get a specif packTemplate ref (in particular for calling admin methods)
222	access(contract)
223	view fun getPackTemplateRef(id: UInt64): &MFLPackTemplate.PackTemplate? {
224		return &self.packTemplates[id] as &MFLPackTemplate.PackTemplate?
225	}
226
227	// Called from MFLPack batchMintPack fct
228	access(account)
229	fun increasePackTemplateCurrentSupply(id: UInt64, nbToMint: UInt32) {
230		let packTemplate = self.getPackTemplateRef(id: id) ?? panic("PackTemplate does not exist")
231		packTemplate.increaseCurrentSupply(nbToMint: nbToMint)
232	}
233
234	// Deprecated: Only here for backward compatibility.
235	access(all)
236	resource interface PackTemplateAdminClaim {}
237
238	access(all)
239	resource PackTemplateAdmin: PackTemplateAdminClaim {
240		access(all)
241		let name: String
242
243		init() {
244			self.name = "PackTemplateAdminClaim"
245		}
246
247		access(PackTemplateAdminAction)
248		fun allowToOpenPacks(id: UInt64) {
249			if let packTemplate = MFLPackTemplate.getPackTemplateRef(id: id) {
250				packTemplate.allowToOpenPacks()
251				emit AllowToOpenPacks(id: id)
252			}
253		}
254
255		access(PackTemplateAdminAction)
256		fun updateMaxSupply(id: UInt64, maxSupply: UInt32) {
257			if let packTemplate = MFLPackTemplate.getPackTemplateRef(id: id) {
258				packTemplate.updateMaxSupply(maxSupply: maxSupply)
259			}
260		}
261
262		access(PackTemplateAdminAction)
263		fun createPackTemplate(name: String, description: String?, maxSupply: UInt32, imageUrl: String, type: String, slots: [Slot]) {
264			let newPackTemplate <- create PackTemplate(name: name, description: description, maxSupply: maxSupply, imageUrl: imageUrl, type: type, slots: slots)
265			let oldPackTemplate <- MFLPackTemplate.packTemplates[newPackTemplate.id] <- newPackTemplate
266			destroy oldPackTemplate
267		}
268	}
269
270	init() {
271		// Set our named paths
272		self.PackTemplateAdminStoragePath = /storage/MFLPackTemplateAdmin
273
274		// Initialize contract fields
275		self.nextPackTemplateID = 1
276		self.packTemplates <-{}
277
278		// Create PackTemplateAdmin resource and save it to storage
279		self.account.storage.save(
280			<-create PackTemplateAdmin(),
281			to: self.PackTemplateAdminStoragePath
282		)
283		emit ContractInitialized()
284	}
285}
286