Smart Contract
StoreManagerV5
A.4bbff461fa8f6192.StoreManagerV5
1import FantastecSwapDataProperties from 0x4bbff461fa8f6192
2import StoreManagerV3 from 0x4bbff461fa8f6192
3
4access(all) contract StoreManagerV5 {
5 access(all) entitlement Manage
6
7 access(all) event SectionAdded(id: UInt64)
8 access(all) event SectionRemoved(id: UInt64)
9
10 access(all) event ProductAdded(id: UInt64)
11 access(all) event ProductRemoved(id: UInt64)
12 access(all) event ProductUpdated(id: UInt64)
13 access(all) event ProductVolumeForSaleDecremented(id: UInt64, newVolumeForSale: UInt64)
14
15 access(all) event SectionItemAdded(id: UInt64, sectionId: UInt64, productId: UInt64)
16 access(all) event SectionItemRemoved(id: UInt64, sectionId: UInt64)
17
18 access(all) event ContractInitiliazed()
19
20 access(all) let StoreManagerDataPath: StoragePath
21
22 access(contract) var nextSectionItemId: UInt64
23 access(contract) var nextSectionId: UInt64
24
25 access(all) struct Product {
26 access(all) let id: UInt64
27 access(all) let description: String
28 access(all) let level: FantastecSwapDataProperties.Level?
29 access(all) let numberOfOptionalNfts: UInt64
30 access(all) let numberOfPacks: UInt64
31 access(all) let numberOfRegularNfts: UInt64
32 access(all) let partner: FantastecSwapDataProperties.Partner?
33 access(all) let season: FantastecSwapDataProperties.Season?
34 access(all) let shortTitle: String
35 access(all) let sku: FantastecSwapDataProperties.Sku?
36 access(all) let sport: FantastecSwapDataProperties.Sport?
37 access(all) let team: FantastecSwapDataProperties.Team?
38 access(all) let themeType: String
39 access(all) let title: String
40 access(all) let releaseDate: UFix64
41 access(all) var volumeForSale: UInt64
42 access(all) let productImageUrl: String
43 access(all) let productVideoUrl: String
44 access(all) let backgroundImageSmallUrl: String
45 access(all) let backgroundImageLargeUrl: String
46 access(all) let featuredImageUrl: String
47 access(all) let featuredVideoUrl: String
48 access(all) var metadata: {String: [{FantastecSwapDataProperties.MetadataElement}]}
49
50 init(
51 id: UInt64,
52 description: String,
53 level: FantastecSwapDataProperties.Level?,
54 numberOfOptionalNfts: UInt64,
55 numberOfPacks: UInt64,
56 numberOfRegularNfts: UInt64,
57 partner: FantastecSwapDataProperties.Partner?,
58 season: FantastecSwapDataProperties.Season?,
59 shortTitle: String,
60 sku: FantastecSwapDataProperties.Sku?,
61 sport: FantastecSwapDataProperties.Sport?,
62 team: FantastecSwapDataProperties.Team?,
63 themeType: String,
64 title: String,
65 releaseDate: UFix64,
66 volumeForSale: UInt64,
67 productImageUrl: String,
68 productVideoUrl: String,
69 backgroundImageSmallUrl: String,
70 backgroundImageLargeUrl: String,
71 featuredImageUrl: String,
72 featuredVideoUrl: String,
73 metadata: {String: [{FantastecSwapDataProperties.MetadataElement}]}
74 ){
75 self.id = id
76 self.description = description
77 self.level = level
78 self.numberOfOptionalNfts = numberOfOptionalNfts
79 self.numberOfPacks = numberOfPacks
80 self.numberOfRegularNfts = numberOfRegularNfts
81 self.partner = partner
82 self.season = season
83 self.shortTitle = shortTitle
84 self.sku = sku
85 self.sport = sport
86 self.team = team
87 self.themeType = themeType
88 self.title = title
89 self.releaseDate = releaseDate
90 self.volumeForSale = volumeForSale
91 self.productImageUrl = productImageUrl
92 self.productVideoUrl = productVideoUrl
93 self.backgroundImageSmallUrl = backgroundImageSmallUrl
94 self.backgroundImageLargeUrl = backgroundImageLargeUrl
95 self.featuredImageUrl = featuredImageUrl
96 self.featuredVideoUrl = featuredVideoUrl
97 self.metadata = metadata
98 }
99
100 access(contract) fun decrementProductVolumeForSale(): UInt64 {
101 if self.volumeForSale == 0 {
102 panic("cannot decrement product for sale as volume for sale is zero - product ID: ".concat(self.id.toString()))
103 }
104 self.volumeForSale = self.volumeForSale - 1
105 return self.volumeForSale
106 }
107 }
108
109 access(all) struct SectionItem {
110 access(all) let id: UInt64
111 access(all) let position: UInt64
112 access(all) var product: Product?
113 access(all) let productId: UInt64
114
115 init(id: UInt64, position: UInt64, productId: UInt64) {
116 self.id = id
117 self.position = position
118 self.product = nil
119 self.productId = productId
120 }
121
122 access(Manage) fun addProduct(product: Product) {
123 self.product = product
124 }
125 }
126
127 access(all) struct Section {
128 access(all) let id: UInt64
129 access(all) let sectionItems: {UInt64: SectionItem}
130 access(all) let position: UInt64
131 access(all) let title: String
132 access(all) let type: String
133
134 init(id: UInt64, position: UInt64, title: String, type: String) {
135 self.id = id
136 self.sectionItems = {}
137 self.position = position
138 self.title = title
139 self.type = type
140 }
141
142 access(Manage) fun addSectionItem(position: UInt64, productId: UInt64): SectionItem {
143 let id = StoreManagerV5.nextSectionItemId
144
145 let sectionItem = SectionItem(id: id, position: position, productId: productId)
146 self.sectionItems.insert(key: id, sectionItem)
147
148 StoreManagerV5.nextSectionItemId = StoreManagerV5.nextSectionItemId + 1
149
150 return sectionItem
151 }
152
153 access(Manage) fun addProductToSectionItem(sectionItemId: UInt64, product: Product): SectionItem? {
154 if let sectionItem = self.sectionItems[sectionItemId] {
155 sectionItem.addProduct(product: product)
156 self.sectionItems[sectionItemId] = sectionItem
157 return sectionItem
158 }
159 return nil
160 }
161
162 access(Manage) fun removeSectionItem(id: UInt64): SectionItem? {
163 return self.sectionItems.remove(key: id)
164 }
165 }
166
167 //-------------------------
168 // Contract level functions
169 //-------------------------
170 access(all) fun getStore(): {UInt64: Section} {
171 return self.getDataManager().getStore()
172 }
173
174 access(all) fun getProduct(productId: UInt64): Product? {
175 return self.getDataManager().getProduct(productId: productId)
176 }
177
178 access(all) fun getProducts(productIds: [UInt64]): [Product] {
179 return self.getDataManager().getProducts(productIds: productIds)
180 }
181
182 access(all) fun getAllProducts(): {UInt64: Product} {
183 return self.getDataManager().getAllProducts()
184 }
185
186 access(all) resource DataManager {
187 access(contract) let products: {UInt64: Product}
188 access(contract) let store: {UInt64: Section}
189
190 access(all) fun getStore(): {UInt64: Section} {
191 let products = self.products
192 let store = self.store
193 let currentBlock = getCurrentBlock()
194
195 store.forEachKey(fun (sectionId: UInt64): Bool {
196 if let section = store[sectionId] {
197 section.sectionItems.forEachKey(fun (sectionItemId: UInt64): Bool {
198 if let sectionItem = section.sectionItems[sectionItemId] {
199 if let product = products[sectionItem.productId] {
200 if product.releaseDate <= currentBlock.timestamp {
201 section.addProductToSectionItem(sectionItemId: sectionItem.id, product: product)
202 }
203 }
204 }
205
206 return true
207 })
208
209 store[sectionId] = section
210 }
211
212 return true
213 })
214
215 return store
216 }
217
218 access(Manage) fun addProduct(
219 id: UInt64,
220 description: String,
221 level: FantastecSwapDataProperties.Level?,
222 numberOfOptionalNfts: UInt64,
223 numberOfPacks: UInt64,
224 numberOfRegularNfts: UInt64,
225 partner: FantastecSwapDataProperties.Partner?,
226 season: FantastecSwapDataProperties.Season?,
227 shortTitle: String,
228 sku: FantastecSwapDataProperties.Sku?,
229 sport: FantastecSwapDataProperties.Sport?,
230 team: FantastecSwapDataProperties.Team?,
231 themeType: String,
232 title: String,
233 releaseDate: UFix64,
234 volumeForSale: UInt64,
235 productImageUrl: String,
236 productVideoUrl: String,
237 backgroundImageSmallUrl: String,
238 backgroundImageLargeUrl: String,
239 featuredImageUrl: String,
240 featuredVideoUrl: String,
241 metadata: {String: [{FantastecSwapDataProperties.MetadataElement}]}
242 ) {
243 let product = Product(
244 id: id,
245 description: description,
246 level: level,
247 numberOfOptionalNfts: numberOfOptionalNfts,
248 numberOfPacks: numberOfPacks,
249 numberOfRegularNfts: numberOfRegularNfts,
250 partner: partner,
251 season: season,
252 shortTitle: shortTitle,
253 sku: sku,
254 sport: sport,
255 team: team,
256 themeType: themeType,
257 title: title,
258 releaseDate: releaseDate,
259 volumeForSale: volumeForSale,
260 productImageUrl: productImageUrl,
261 productVideoUrl: productVideoUrl,
262 backgroundImageSmallUrl: backgroundImageSmallUrl,
263 backgroundImageLargeUrl: backgroundImageLargeUrl,
264 featuredImageUrl: featuredImageUrl,
265 featuredVideoUrl: featuredVideoUrl,
266 metadata: metadata
267 )
268 self.products[product.id] = product
269 emit ProductAdded(id: product.id)
270 }
271
272 access(Manage) fun decrementProductVolumeForSale(productId: UInt64) {
273 let newVolumeForSale = self.products[productId]?.decrementProductVolumeForSale()
274 if (newVolumeForSale != nil) {
275 emit ProductVolumeForSaleDecremented(id: productId, newVolumeForSale: newVolumeForSale!)
276 }
277 }
278
279 access(all) fun getProduct(productId: UInt64): Product? {
280 return self.products[productId]
281 }
282
283 access(all) fun getProducts(productIds: [UInt64]): [Product] {
284 let products: [Product] = []
285 for productId in productIds {
286 let product = self.getProduct(productId: productId)
287 if (product != nil) {
288 products.append(product!)
289 }
290 }
291 return products
292 }
293
294 access(all) fun getAllProducts(): {UInt64: Product} {
295 return self.products
296 }
297
298 access(Manage) fun removeProduct(productId: UInt64) {
299 let store = self.store
300 let sectionItemsToRemove: {UInt64: UInt64} = {}
301 store.forEachKey(fun (sectionId: UInt64): Bool {
302 if let section = store[sectionId] {
303 section.sectionItems.forEachKey(fun (sectionItemId: UInt64): Bool {
304 if let sectionItem = section.sectionItems[sectionItemId] {
305 if sectionItem.productId == productId {
306 sectionItemsToRemove[section.id] = sectionItem.id
307 }
308 }
309
310 return true
311 })
312 }
313
314 return true
315 })
316
317 // Remove all section items that are associated with a removed product
318 for sectionId in sectionItemsToRemove.keys {
319 let sectionItemId = sectionItemsToRemove[sectionId]
320 self.removeSectionItemFromSection(sectionId: sectionId, sectionItemId: sectionItemId!)
321 // if the section is now empty, remove it
322 let updatedSection = store[sectionId]
323 if (updatedSection!.sectionItems.length == 0) {
324 self.removeSection(sectionId: sectionId)
325 }
326 }
327
328 self.products.remove(key: productId)
329 emit ProductUpdated(id: productId)
330 }
331
332 access(Manage) fun addSection(position: UInt64, title: String, type: String): UInt64 {
333 let id = StoreManagerV5.nextSectionId
334 let section = Section(id: id, position: position, title: title, type: type)
335
336 self.store[section.id] = section
337
338 emit SectionAdded(id: id)
339 StoreManagerV5.nextSectionId = StoreManagerV5.nextSectionId + 1
340
341 return id
342 }
343
344 access(all) fun getSection(sectionId: UInt64): Section? {
345 return self.store[sectionId]
346 }
347
348 access(Manage) fun removeSection(sectionId: UInt64) {
349 self.store.remove(key: sectionId)
350 emit SectionRemoved(id: sectionId)
351 }
352
353 access(Manage) fun addSectionItemToSection(sectionId: UInt64, position: UInt64, productId: UInt64): UInt64 {
354 let sectionItem = self.store[sectionId]?.addSectionItem(position: position, productId: productId)
355 sectionItem ?? panic("no section found with ID ".concat(sectionId.toString()))
356 emit SectionItemAdded(id: sectionItem!.id, sectionId: sectionId, productId: productId)
357
358 return sectionItem!.id
359 }
360
361 access(Manage) fun removeSectionItemFromSection(sectionId: UInt64, sectionItemId: UInt64) {
362 let sectionItem = self.store[sectionId]?.removeSectionItem(id: sectionItemId)
363 sectionItem ?? panic("no section found with ID ".concat(sectionId.toString()))
364 emit SectionItemRemoved(id: sectionItemId, sectionId: sectionId)
365 }
366
367 init(_ products: {UInt64: Product}, _ sections: {UInt64: Section}) {
368 self.products = products
369 self.store = sections
370 }
371 }
372
373 access(contract) fun setDataManager() {
374 let oldDataManager <- self.account.storage.load<@DataManager>(from: self.StoreManagerDataPath)
375 var oldProducts = oldDataManager?.products ?? {}
376 var oldStore = oldDataManager?.store ?? {}
377 self.account.storage.save<@DataManager>(<- create DataManager(oldProducts, oldStore), to: self.StoreManagerDataPath)
378 destroy oldDataManager
379 }
380
381 access(contract) fun getDataManager(): &DataManager {
382 return self.account.storage.borrow<&DataManager>(from: self.StoreManagerDataPath)!
383 }
384
385 init() {
386 self.nextSectionItemId = 1
387 self.nextSectionId = 1
388
389 self.StoreManagerDataPath = /storage/StoreManagerV5Data
390
391 // self.setDataManager()
392 emit ContractInitiliazed()
393 }
394}
395
396