Smart Contract
NFTSalesCapped
A.a49cc0ee46c54bfb.NFTSalesCapped
1import FungibleToken from 0xf233dcee88fe0abe
2import REVV from 0xd01e482eb680ec9f
3import SHRD from 0xd01e482eb680ec9f
4import MotoGPAdmin from 0xa49cc0ee46c54bfb
5import MotoGPCard from 0xa49cc0ee46c54bfb
6import CardMintAccess from 0xa49cc0ee46c54bfb
7import ContractVersion from 0xa49cc0ee46c54bfb
8import SHRDMintAccess from 0xd01e482eb680ec9f
9import MotoGPCardMetadata from 0xa49cc0ee46c54bfb
10import MotoGPCardSerialPoolV2 from 0xa49cc0ee46c54bfb
11import Pausable from 0xb223b2bfe4b8ffb5
12
13pub contract NFTSalesCapped : ContractVersion {
14
15 pub fun getVersion(): String {
16 return "1.0.8"
17 }
18
19 pub event OrderIdRegistered(orderId: String)
20 pub event PackOpened(cardIDs: [UInt64], serials: [UInt64], shrdAmount: UFix64)
21
22 pub resource OpenedPack{
23 pub var collection: @MotoGPCard.Collection
24 pub var vault: @SHRD.Vault
25 init(collection_: @MotoGPCard.Collection, vault_: @SHRD.Vault) {
26 self.collection <- collection_
27 self.vault <- vault_
28 }
29 destroy() {
30 // Don't allow destruction if not empty
31 assert(self.collection.getIDs().length == 0, message: "OpenedPack's card collection is not empty")
32 assert(self.vault.balance == 0.0, message: "OpenedPack's shrd vault is not empty")
33 destroy self.collection
34 destroy self.vault
35 }
36 }
37
38 pub enum SalesOpenOverride: UInt8 {
39 pub case NoOverride
40 pub case ForceOpen
41 pub case ForceClose
42 }
43
44 pub resource Sales {
45 pub let id: UInt64
46 pub let name: String
47 pub var salesOpenOverride: UInt8 // Used to override the blocktime-based open status, for emergency situations, e.g. block start time doesn't sync with IRL time
48 pub var totalSupply: UInt64
49 pub var maxSHRD: UFix64 //The maximum allowed amount of SHRD which can be minted by this Sales
50 pub var mintedSHRD: UFix64 //Keeps count of how much SHRD has been minted
51 access(self) var shrdPerGrade: {String:UFix64} // grade (rarity, e.g. Legendary) => amount of SHRD
52 pub var cardsPerPack: UInt64 //how many cards will be minted when a pack is opened
53 pub let nonces: {Address: UInt64} //how many packs have been opened for an account
54 pub var price: UFix64 // for use when paying with Vault
55 pub var publicKey: String // used to verify the signature during an open pack call
56 pub var signatureAlgorithm: UInt8 // SignatureAlorithm type is not storable
57 pub var startTime: UFix64 // start time in unix time stamp seconds (not milliseconds), to be compared to block time. Note: block timestamps are UFix64.
58 pub var endTime: UFix64 // end time in unix time stamp seconds (not milliseconds), to be compared to block time. Note: block timestamps are UFix64.
59 pub var maxPerWallet: UInt64 // max number of cards a buyer can mint
60 pub var cardCountByWallet: {Address: UInt64} // keeps track of how many cards a buyer has minted
61 pub var sold: UInt64 // the number of cards minted from this Sales resource
62 access(self) var cardTypeWeights: [[UInt32]] // A list of bucket card probability weights. Each inner array holds the weights for one bucket
63 access(self) var cardTypes: [[UInt64]] // A list of bucket card types. Each inner array holds the types for one bucket. Needs to be ordered to match cardTypeWeights's order
64 pub let pausableCap: Capability<&{Pausable.PausableExternal}>
65 init(
66 name: String,
67 totalSupply: UInt64,
68 maxSHRD: UFix64,
69 shrdPerGrade: {String: UFix64},
70 cardsPerPack: UInt64,
71 price: UFix64,
72 startTime: UFix64,
73 endTime: UFix64,
74 maxPerWallet: UInt64,
75 cardTypeWeights: [[UInt32]], // If empty, should be [], not [[],[],[]]
76 cardTypes: [[UInt64]], // If empty, should be [], not [[],[],[]]
77 pausableCap: Capability<&{Pausable.PausableExternal}>
78 ) {
79 pre {
80 name.length > 0 : "name has zero length"
81 NFTSalesCapped.isEqual2DArrayLengths(cardTypeWeights, cardTypes) : "inconsistent initial card type weight array lengths"
82 }
83 self.id = self.uuid
84 self.salesOpenOverride = SalesOpenOverride.NoOverride.rawValue
85 self.name = name
86 self.totalSupply = totalSupply
87 self.maxSHRD = maxSHRD
88 self.mintedSHRD = 0.0
89 self.shrdPerGrade = shrdPerGrade
90 self.cardsPerPack = cardsPerPack
91 self.nonces = {}
92 self.price = price
93 self.publicKey = ""
94 self.signatureAlgorithm = SignatureAlgorithm.ECDSA_P256.rawValue// To convert back to enum, use: SignatureAlgorithm(rawValue: self.signatureAlgorithm)
95 self.startTime = startTime
96 self.endTime = endTime
97 self.maxPerWallet = maxPerWallet
98 self.cardCountByWallet = {}
99 self.sold = 0
100 self.cardTypeWeights = cardTypeWeights
101 self.cardTypes = cardTypes
102 self.pausableCap = pausableCap
103 }
104
105 access(contract) fun addCardTypeWeights(cardTypeWeights: [UInt32], cardTypes: [UInt64]){
106 pre {
107 cardTypeWeights.length == cardTypes.length : "inconsistent card type weight array lengths"
108 }
109 self.cardTypeWeights.append(cardTypeWeights)
110 self.cardTypes.append(cardTypes)
111 }
112
113 access(contract) fun removeCardTypeWeights(at index: UInt64) {
114 self.cardTypeWeights.remove(at: index)
115 self.cardTypes.remove(at: index)
116 }
117
118 access(contract) fun clearCardTypeWeights() {
119 self.cardTypeWeights = []
120 self.cardTypes = []
121 }
122
123 access(contract) fun setSalesOpenOverride(state: SalesOpenOverride) {
124 self.salesOpenOverride = state.rawValue
125 }
126
127 access(contract) fun setMaxSHRD(maxSHRD: UFix64) {
128 self.maxSHRD = maxSHRD
129 }
130
131 access(contract) fun setTotalSupply(totalSupply: UInt64) {
132 self.totalSupply = totalSupply
133 }
134
135 access(contract) fun setStartTime(startTime: UFix64) {
136 self.startTime = startTime
137 }
138
139 access(contract) fun setEndTime(endTime: UFix64) {
140 self.endTime = endTime
141 }
142
143 access(contract) fun setPublicKey(publicKey: String, signatureAlgorithm: SignatureAlgorithm) {
144 self.publicKey = publicKey
145 self.signatureAlgorithm = signatureAlgorithm.rawValue
146 }
147
148 access(contract) fun setMaxPerWallet(maxPerWallet: UInt64) {
149 self.maxPerWallet = maxPerWallet
150 }
151
152 access(contract) fun setCardsPerPack(cardsPerPack: UInt64) {
153 self.cardsPerPack = cardsPerPack
154 }
155
156 access(contract) fun setSHRDPerGrade(shrdPerGrade: {String: UFix64}) {
157 self.shrdPerGrade = shrdPerGrade
158 }
159
160 access(contract) fun setPrice(price: UFix64) {
161 self.price = price
162 }
163
164 pub fun getSHRDPerGrade(): {String: UFix64} {
165 return self.shrdPerGrade
166 }
167
168 pub fun isOpen(): Bool {
169 if self.salesOpenOverride == SalesOpenOverride.ForceOpen.rawValue {
170 return true
171 }
172 if self.salesOpenOverride == SalesOpenOverride.ForceClose.rawValue {
173 return false
174 }
175
176 let ts = getCurrentBlock().timestamp
177 return self.startTime <= ts && self.endTime >= ts
178 }
179
180 pub fun openPacksWithCreditCardPayment(
181 signature: String,
182 orderId: String,
183 address: Address,
184 quantity: UInt64,
185 hashAlgorithm: HashAlgorithm
186 ): @OpenedPack {
187
188 pre {
189 !self.pausableCap.borrow()!.isPaused(): "Invalid: Sales is paused"
190 NFTSalesCapped.orderIds[orderId] == nil : "orderId already used"
191 }
192
193 NFTSalesCapped.orderIds[orderId] = getCurrentBlock().height
194
195 let message = address.toString().concat(orderId).concat(self.uuid.toString()).concat(quantity.toString())
196
197 let isValid = NFTSalesCapped.isValidSignature(
198 publicKey: self.publicKey,
199 signatureAlgorithm: SignatureAlgorithm(rawValue: self.signatureAlgorithm)!,
200 hashAlgorithm: hashAlgorithm,
201 signature: signature,
202 message: message)
203 if isValid == false {
204 panic("Signature isn't valid")
205 }
206
207 emit OrderIdRegistered(orderId: orderId)
208
209 let res <- self.openPack(
210 signature: signature,
211 address: address,
212 quantity: quantity,
213 message: message
214 )
215
216 return <- res
217 }
218
219 pub fun openPacksWithVaultPayment(
220 signature: String,
221 revvVault: @REVV.Vault,
222 address: Address,
223 quantity: UInt64,
224 hashAlgorithm: HashAlgorithm
225 ): @OpenedPack {
226
227 pre {
228 !self.pausableCap.borrow()!.isPaused(): "Invalid: Sales is paused"
229 self.isOpen() : "Sales is not open"
230 revvVault.balance == self.price * UFix64(quantity) : "revvVault balance doesn't match price * quantity"
231 }
232
233 NFTSalesCapped.paymentReceiverCap!.borrow()!.deposit(from: <- revvVault)
234
235 if self.nonces[address] == nil {
236 self.nonces[address] = UInt64(1)
237 } else {
238 self.nonces[address] = self.nonces[address]! + UInt64(1)
239 }
240
241 let message = self.nonces[address]!.toString().concat(address.toString()).concat(self.uuid.toString())
242
243 let isValid = NFTSalesCapped.isValidSignature(
244 publicKey: self.publicKey,
245 signatureAlgorithm: SignatureAlgorithm(rawValue: self.signatureAlgorithm)!,
246 hashAlgorithm: hashAlgorithm,
247 signature: signature,
248 message: message)
249 if isValid == false {
250 panic("Signature isn't valid")
251 }
252
253 let res <- self.openPack(
254 signature: signature,
255 address: address,
256 quantity: quantity,
257 message: message,
258 )
259
260 return <- res
261 }
262
263 access(contract) fun openPack( // TODO: change to access(self)
264 signature: String,
265 address: Address,
266 quantity: UInt64,
267 message: String
268 ): @OpenedPack {
269
270 if (self.sold + (quantity * self.cardsPerPack)) > self.totalSupply {
271 panic("totalSupply exceeded")
272 }
273
274 // Mint cards
275 let cardIDsAndSerials = self.generateCardIDsAndSerials(signature: signature, quantity: quantity)
276
277 let cardIDs = cardIDsAndSerials[0]
278 let serials = cardIDsAndSerials[1]
279 let collection:@MotoGPCard.Collection <- NFTSalesCapped.mintCards(cardIDs: cardIDs, serials: serials)
280
281 // Mint shrd
282 var shrdAmount = self.calculateSHRDAmount(cardIDs: cardIDs)
283 let vault <- SHRD.createEmptyVault() as! @SHRD.Vault
284
285 if (shrdAmount > 0.0) {
286 vault.deposit(from: <- NFTSalesCapped.mintSHRD(amount: shrdAmount))
287 }
288
289 // Check and update minted card counts
290 self.sold = self.sold + UInt64(cardIDs.length)
291
292 if self.cardCountByWallet[address] == nil {
293 self.cardCountByWallet[address] = 0
294 }
295 let newCountForWallet = self.cardCountByWallet[address]! + UInt64(cardIDs.length)
296 if newCountForWallet > self.maxPerWallet {
297 panic("max cards exceeded for this wallet")
298 }
299 self.cardCountByWallet[address] = newCountForWallet
300
301 emit PackOpened(cardIDs: cardIDs, serials: serials, shrdAmount: shrdAmount)
302
303 return <- create OpenedPack(collection_: <- collection, vault_: <- vault)
304 }
305
306 pub fun getNonce(address: Address): UInt64 {
307 return self.nonces[address] ?? 0 as UInt64
308 }
309
310 access(contract) fun digestToUInt64(digest: [UInt8]): UInt64 {
311 return (UInt64(digest[0]) << UInt64(56))
312 + (UInt64(digest[1]) << UInt64(48))
313 + (UInt64(digest[2]) << UInt64(40))
314 + (UInt64(digest[3]) << UInt64(32))
315 + (UInt64(digest[4]) << UInt64(24))
316 + (UInt64(digest[5]) << UInt64(16))
317 + (UInt64(digest[6]) << UInt64(8))
318 + (UInt64(digest[7]))
319 }
320
321 access(contract) fun generateCardIDsAndSerials(signature: String, quantity: UInt64): [[UInt64]; 2] {
322 let res: [[UInt64]; 2] = [[],[]]
323 var index:UInt64 = 0
324 var digest:[UInt8] = signature.decodeHex()
325 let numCards = self.cardsPerPack * quantity
326 let numBuckets = UInt64(self.cardTypeWeights.length)
327
328 while index < numCards {
329 let bucketIndex = index % numBuckets
330
331 digest = index == 0 ? digest : HashAlgorithm.KECCAK_256.hash(digest)
332 var n = self.digestToUInt64(digest: digest)
333 let cardID = self.generateSingleCardIDFromDigest(n: n, bucketIndex: bucketIndex)
334 res[0].append(cardID)
335
336 digest = HashAlgorithm.KECCAK_256.hash(digest)
337 n = self.digestToUInt64(digest: digest)
338 res[1].append(MotoGPCardSerialPoolV2.pickSerial(n: n, cardID: cardID))
339
340 index = index + 1
341 }
342 return res
343 }
344
345 access(contract) fun generateSingleCardIDFromDigest(n: UInt64, bucketIndex: UInt64): UInt64 {
346 let cardTypeWeights = self.cardTypeWeights[bucketIndex]
347 let totalWeight = cardTypeWeights[cardTypeWeights.length - 1]
348 let r = n % UInt64(totalWeight)
349 for i, weight in cardTypeWeights {
350 if r <= UInt64(weight) {
351 return self.cardTypes[bucketIndex][i]
352 }
353 }
354 panic("no cardType matched to weight: ".concat(r.toString().concat(" with totalWeight: ").concat(totalWeight.toString())))
355 }
356
357 access(contract) fun calculateSHRDAmount(cardIDs: [UInt64]): UFix64 {
358 if self.mintedSHRD >= self.maxSHRD {
359 return 0.0
360 }
361 var res = 0.0
362 for cardID in cardIDs {
363 let metadata = MotoGPCardMetadata.getMetadataForCardID(cardID: cardID) ?? panic("cardID ".concat(cardID.toString()).concat(" has no matching metadata"))
364 let grade = metadata.data["grade"] ?? panic("cardID ".concat(cardID.toString()).concat(" metadata has no grade"))
365 let shrdAmount = self.shrdPerGrade[grade] ?? 0.0
366 res = res + shrdAmount
367 }
368 if res + self.mintedSHRD > self.maxSHRD {
369 res = self.maxSHRD - self.mintedSHRD
370 }
371 self.mintedSHRD = self.mintedSHRD + res
372 return res
373 }
374 }
375
376 pub resource interface SalesCollectionPublic {
377 pub fun getIDs(): [UInt64]
378 pub fun borrowSales(salesID: UInt64): &Sales
379 pub fun getCardCount(salesID: UInt64): UInt64
380 }
381
382 pub resource SalesCollection: SalesCollectionPublic {
383
384 pub var salesMap: @{UInt64: Sales}
385
386 pub fun addSales(sales: @Sales) {
387 pre {
388 NFTSalesCapped.isPaymentReceiverCapSet() == true : "payment receiver is not set"
389 }
390 let salesID = sales.id
391 let oldItem <- self.salesMap[salesID] <- sales
392 // TODO: Add event
393 destroy oldItem
394 }
395 pub fun removeSales(salesID: UInt64): @Sales {
396 let sales <- self.salesMap.remove(key: salesID) ?? panic("missing Sales")
397 // TODO: Add event
398 return <- sales
399 }
400
401 pub fun setSalesOpenOverride(salesID: UInt64, state: NFTSalesCapped.SalesOpenOverride) {
402 self.borrowSales(salesID: salesID).setSalesOpenOverride(state: state)
403 }
404 pub fun setTotalSupply(salesID: UInt64, totalSupply: UInt64) {
405 self.borrowSales(salesID: salesID).setTotalSupply(totalSupply: totalSupply)
406 }
407 pub fun setMaxSHRD(salesID: UInt64, maxSHRD: UFix64) {
408 self.borrowSales(salesID: salesID).setMaxSHRD(maxSHRD: maxSHRD)
409 }
410 pub fun setPublicKey(salesID: UInt64, publicKey:String, signatureAlgorithm: SignatureAlgorithm) {
411 self.borrowSales(salesID: salesID).setPublicKey(publicKey: publicKey, signatureAlgorithm: signatureAlgorithm)
412 }
413 pub fun setMaxPerWallet(salesID: UInt64, maxPerWallet: UInt64) {
414 self.borrowSales(salesID: salesID).setMaxPerWallet(maxPerWallet: maxPerWallet)
415 }
416 pub fun setCardPerPack(salesID: UInt64, cardsPerPack: UInt64) {
417 self.borrowSales(salesID: salesID).setCardsPerPack(cardsPerPack: cardsPerPack)
418 }
419 pub fun setStartTime(salesID: UInt64, startTime: UFix64) {
420 self.borrowSales(salesID: salesID).setStartTime(startTime: startTime)
421 }
422 pub fun setEndTime(salesID: UInt64, endTime: UFix64) {
423 self.borrowSales(salesID: salesID).setEndTime(endTime: endTime)
424 }
425 pub fun addCardTypeWeights(salesID: UInt64, cardTypeWeights: [UInt32], cardTypes: [UInt64]) {
426 self.borrowSales(salesID: salesID).addCardTypeWeights(cardTypeWeights: cardTypeWeights, cardTypes: cardTypes)
427 }
428 pub fun setSHRDPerGrade(salesID: UInt64, shrdPerGrade: {String: UFix64}) {
429 self.borrowSales(salesID: salesID).setSHRDPerGrade(shrdPerGrade: shrdPerGrade)
430 }
431 pub fun setPrice(salesID: UInt64, price: UFix64) {
432 self.borrowSales(salesID: salesID).setPrice(price: price)
433 }
434 pub fun removeCardTypeWeights(salesID: UInt64, at index: UInt64) {
435 self.borrowSales(salesID: salesID).removeCardTypeWeights(at: index)
436 }
437 pub fun clearCardTypeWeights(salesID: UInt64) {
438 self.borrowSales(salesID: salesID).clearCardTypeWeights()
439 }
440 pub fun getCardCount(salesID: UInt64): UInt64 {
441 return self.borrowSales(salesID: salesID).sold
442 }
443 pub fun getNonceForSales(salesID: UInt64, address: Address): UInt64 {
444 return self.borrowSales(salesID: salesID).getNonce(address: address)
445 }
446 pub fun getIDs(): [UInt64] {
447 return self.salesMap.keys
448 }
449 pub fun borrowSales(salesID: UInt64): &Sales {
450 return (&self.salesMap[salesID] as &Sales?)!
451 }
452 init() {
453 self.salesMap <- {}
454 }
455 destroy(){
456 destroy self.salesMap
457 }
458 }
459
460 pub fun isSHRDMintProxyCapSet(): Bool {
461 return self.shrdMintProxyCap != nil
462 }
463
464 pub fun isCardMintProxyCapSet(): Bool {
465 return self.cardMintProxyCap != nil
466 }
467
468 pub fun isPaymentReceiverCapSet(): Bool {
469 return self.paymentReceiverCap != nil
470 }
471
472 pub fun isOrderIdUsed(orderId: String): Bool {
473 return NFTSalesCapped.orderIds[orderId] != nil
474 }
475
476 pub fun getBlockHeightForOrderId(orderId: String): UInt64? {
477 return NFTSalesCapped.orderIds[orderId]
478 }
479
480 pub fun createSales(
481 adminRef: &MotoGPAdmin.Admin,
482 name: String,
483 totalSupply: UInt64,
484 maxSHRD: UFix64,
485 shrdPerGrade: {String: UFix64},
486 cardsPerPack: UInt64,
487 price: UFix64,
488 startTime: UFix64,
489 endTime: UFix64,
490 maxPerWallet: UInt64,
491 cardTypeWeights: [[UInt32]],
492 cardTypes: [[UInt64]],
493 pausableCap: Capability<&{Pausable.PausableExternal}>
494 ): @Sales {
495 pre {
496 adminRef != nil : "adminRef is nil"
497 }
498 return <- create Sales(
499 name: name,
500 totalSupply: totalSupply,
501 maxSHRD: maxSHRD,
502 shrdPerGrade: shrdPerGrade,
503 cardsPerPack: cardsPerPack,
504 price: price,
505 startTime: startTime,
506 endTime: endTime,
507 maxPerWallet: maxPerWallet,
508 cardTypeWeights: cardTypeWeights,
509 cardTypes: cardTypes,
510 pausableCap: pausableCap
511 )
512 }
513
514 pub fun createSalesCollection(adminRef: &MotoGPAdmin.Admin): @SalesCollection {
515 pre {
516 adminRef != nil : "adminRef is nil"
517 }
518 return <- create SalesCollection()
519 }
520
521 pub fun setCardMintProxyCapability(adminRef: &MotoGPAdmin.Admin, capability: Capability<&CardMintAccess.MintProxy{CardMintAccess.MintProxyPrivate}>) {
522 pre {
523 adminRef != nil : "adminRef is nil"
524 capability.check() == true : "capability.check() is false"
525 capability!.borrow() != nil : "can't borrow capability"
526 }
527 self.cardMintProxyCap = capability
528 }
529
530 pub fun setSHRDMintProxyCapability(adminRef: &MotoGPAdmin.Admin, capability: Capability<&SHRDMintAccess.MintProxy{SHRDMintAccess.MintProxyPrivate}>) {
531 pre {
532 adminRef != nil : "adminRef is nil"
533 capability.check() == true : "capability.check() is false"
534 capability!.borrow() != nil : "can't borrow capability"
535 }
536 self.shrdMintProxyCap = capability
537 }
538
539 pub fun setPaymentReceiverCapability(adminRef: &MotoGPAdmin.Admin, capability: Capability<&{FungibleToken.Receiver}>) {
540 pre {
541 adminRef != nil : "adminRef is nil"
542 }
543 self.paymentReceiverCap = capability
544 }
545
546 access(contract) fun isEqual2DArrayLengths(_ array1: [[AnyStruct]], _ array2: [[AnyStruct]]): Bool {
547 if (array1.length != array2.length) {
548 return false
549 }
550
551 for i, innerArray1 in array1 {
552 if (innerArray1.length != array2[i].length) {
553 return false
554 }
555 }
556
557 return true
558 }
559
560 access(contract) fun isValidSignature(
561 publicKey: String,
562 signatureAlgorithm: SignatureAlgorithm,
563 hashAlgorithm: HashAlgorithm,
564 signature: String,
565 message: String): Bool {
566 let pk = PublicKey(
567 publicKey: publicKey.decodeHex(),
568 signatureAlgorithm: signatureAlgorithm
569 )
570
571 let isValid = pk.verify(
572 signature: signature.decodeHex(),
573 signedData: message.utf8,
574 domainSeparationTag: "FLOW-V0.0-user",
575 hashAlgorithm: hashAlgorithm
576 )
577 return isValid
578 }
579
580 access(contract) fun mintSHRD(amount: UFix64): @SHRD.Vault {
581 return <- self.shrdMintProxyCap!.borrow()!.mint(amount: amount)
582 }
583
584 access(contract) fun mintCards(cardIDs: [UInt64], serials: [UInt64]): @MotoGPCard.Collection {
585 pre {
586 cardIDs.length == serials.length : "Inconsistent array lengths"
587 }
588
589 let collection <- MotoGPCard.createEmptyCollection()
590 for index, cardID in cardIDs {
591 let card <- self.cardMintProxyCap!.borrow()!.mint(cardID: cardID, serial: serials[index])
592 collection.deposit(token: <- card)
593 }
594 return <- collection
595 }
596
597 pub let SalesCollectionStoragePath: StoragePath
598 pub let SalesCollectionPublicPath: PublicPath
599 pub let SalesCollectionPrivatePath: PrivatePath
600 pub let pathIdentifier:String
601 pub let orderIds: {String:UInt64}
602 access(contract) var shrdMintProxyCap: Capability<&SHRDMintAccess.MintProxy{SHRDMintAccess.MintProxyPrivate}>?
603 access(contract) var cardMintProxyCap: Capability<&CardMintAccess.MintProxy{CardMintAccess.MintProxyPrivate}>?
604 access(contract) var paymentReceiverCap: Capability<&{FungibleToken.Receiver}>?
605
606
607 init() {
608 self.orderIds = {}
609 self.shrdMintProxyCap = nil
610 self.cardMintProxyCap = nil
611 self.paymentReceiverCap = nil
612 self.SalesCollectionStoragePath = /storage/salesCappedCollection
613 self.SalesCollectionPublicPath = /public/salesCappedCollection
614 self.SalesCollectionPrivatePath = /private/salesCappedCollection
615 self.pathIdentifier = "SalesCapped"
616 }
617
618}