Smart Contract
TenantService
A.965411a02ca21b87.TenantService
1
2import NonFungibleToken from 0x1d7e57aa55817448
3
4pub contract TenantService: NonFungibleToken {
5
6 // basic data about the tenant
7 pub let id: String
8 pub let name: String
9 pub let description: String
10 pub var closed: Bool
11
12 // NFT
13 pub var totalSupply: UInt64
14
15 // paths
16 access(all) let ADMIN_OBJECT_PATH: StoragePath
17 access(all) let PRIVATE_NFT_COLLECTION_PATH: StoragePath
18 access(all) let PUBLIC_NFT_COLLECTION_PATH: PublicPath
19 access(all) let PUBLIC_NFT_COLLECTION_PATH_CUSTOM: PublicPath
20
21 // archetypes
22 access(self) let archetypes: {UInt64: Archetype}
23 access(self) let archetypeAdmins: @{UInt64: ArchetypeAdmin}
24 access(self) var archetypeSeq: UInt64
25 access(self) let artifactsByArchetype: {UInt64: {UInt64: Bool}} // archetypeId -> {artifactId: true}
26
27 // artifacts
28 access(self) let artifacts: {UInt64: Artifact}
29 access(self) let artifactAdmins: @{UInt64: ArtifactAdmin}
30 access(self) var artifactSeq: UInt64
31 access(self) var nextNftSerialNumber: {UInt64: UInt64}
32 access(self) let setsByArtifact: {UInt64: {UInt64: Bool}} // artifactId -> {setId: true}
33 access(self) let faucetsByArtifact: {UInt64: {UInt64: Bool}} // artifactId -> {faucetId: true}
34
35 // sets
36 access(self) let sets: {UInt64: Set}
37 access(self) let setAdmins: @{UInt64: SetAdmin}
38 access(self) var setSeq: UInt64
39 access(self) let artifactsBySet: {UInt64: {UInt64: Bool}} // setId -> {artifactId: true}
40 access(self) let faucetsBySet: {UInt64: {UInt64: Bool}} // setId -> {faucetId: true}
41
42 // prints
43 access(self) let prints: {UInt64: Print}
44 access(self) let printAdmins: @{UInt64: PrintAdmin}
45 access(self) var printSeq: UInt64
46
47 // faucets
48 access(self) let faucets: {UInt64: Faucet}
49 access(self) let faucetAdmins: @{UInt64: FaucetAdmin}
50 access(self) var faucetSeq: UInt64
51
52 // tenant events
53 pub event TenantClosed()
54
55 // NFT events
56 pub event ContractInitialized()
57 pub event Withdraw(id: UInt64, from: Address?)
58 pub event Deposit(id: UInt64, to: Address?)
59
60 init(
61 tenantId: String,
62 tenantName: String,
63 tenantDescription: String,
64 ADMIN_OBJECT_PATH: StoragePath,
65 PRIVATE_NFT_COLLECTION_PATH: StoragePath,
66 PUBLIC_NFT_COLLECTION_PATH: PublicPath,
67 PUBLIC_NFT_COLLECTION_PATH_CUSTOM: PublicPath
68 ) {
69 self.id = tenantId
70 self.name = tenantName
71 self.description = tenantDescription
72 self.closed = false
73
74 self.archetypes = {}
75 self.archetypeAdmins <- {}
76 self.archetypeSeq = 1
77 self.artifactsByArchetype = {}
78
79 self.artifacts = {}
80 self.artifactAdmins <- {}
81 self.artifactSeq = 1
82 self.nextNftSerialNumber = {}
83 self.setsByArtifact = {}
84 self.faucetsByArtifact = {}
85
86 self.sets = {}
87 self.setAdmins <- {}
88 self.setSeq = 1
89 self.artifactsBySet = {}
90 self.faucetsBySet = {}
91
92 self.prints = {}
93 self.printAdmins <- {}
94 self.printSeq = 1
95
96 self.faucets = {}
97 self.faucetAdmins <- {}
98 self.faucetSeq = 1
99
100 self.totalSupply = 0
101
102 self.OBJECT_TYPE_MASK = UInt64.max << 55
103 self.SEQUENCE_MASK = (UInt64.max << UInt64(9)) >> UInt64(9)
104
105 self.ADMIN_OBJECT_PATH = ADMIN_OBJECT_PATH
106 self.PRIVATE_NFT_COLLECTION_PATH = PRIVATE_NFT_COLLECTION_PATH
107 self.PUBLIC_NFT_COLLECTION_PATH = PUBLIC_NFT_COLLECTION_PATH
108 self.PUBLIC_NFT_COLLECTION_PATH_CUSTOM = PUBLIC_NFT_COLLECTION_PATH_CUSTOM
109
110 // create a collection for the admin
111 self.account.save<@ShardedCollection>(<- TenantService.createEmptyShardedCollection(numBuckets: 32), to: TenantService.PRIVATE_NFT_COLLECTION_PATH)
112
113 // Create a public capability for the Collection
114 self.account.link<&{NonFungibleToken.CollectionPublic}>(TenantService.PUBLIC_NFT_COLLECTION_PATH, target: TenantService.PRIVATE_NFT_COLLECTION_PATH)
115 self.account.link<&{CollectionPublic}>(TenantService.PUBLIC_NFT_COLLECTION_PATH_CUSTOM, target: TenantService.PRIVATE_NFT_COLLECTION_PATH)
116
117 // put the admin in storage
118 self.account.save<@TenantAdmin>(<- create TenantAdmin(), to: TenantService.ADMIN_OBJECT_PATH)
119
120 emit ContractInitialized()
121 }
122
123 pub enum ObjectType: UInt8 {
124 pub case UNKNOWN
125
126 // An Archetype is a high level organizational unit for a type of NFT. For instance, in the
127 // case that the Tenant is a company dealing with professional sports they might have an Archetype
128 // for each of the sports that they support, ie: Basketball, Baseball, Football, etc.
129 //
130 pub case ARCHETYPE
131
132 // An Artifact is the actual object that is minted as an NFT. It contains all of the meta data data
133 // and a reference to the Archetype that it belongs to.
134 //
135 pub case ARTIFACT
136
137 // NFTs can be minted into a Set. A set could be something along the lines of "Greatest Pitchers",
138 // "Slam Dunk Artists", or "Running Backs" (continuing with the sports theme from above). NFT do
139 // not have to be minted into a set. Also, an NFT could be minted from an Artifact by itself, and
140 // in another instance as part of a set - so that the NFT references the same Artifact, but only
141 // one of them belongs to the Set.
142 //
143 pub case SET
144
145 // A Print reserves a block of serial numbers for minting at a later time. It is associated with
146 // a single Artifact and when the Print is minted it reserves the next serial number through however
147 // many serial numbers are to be reserved. NFTs can then later be minted from the Print and will
148 // be given the reserved serial numbers.
149 //
150 pub case PRINT
151
152 // A Faucet is similar to a Print except that it doesn't reserve a block of serial numbers, it merely
153 // mints NFTs from a given Artifact on demand. A Faucet can have a maxMintCount or be unbound and
154 // mint infinitely (or however many NFTs are allowed to be minted for the Artifact that it is bound to).
155 //
156 pub case FAUCET
157
158 // An NFT holds metadata, a reference to it's Artifact (and therefore Archetype), a reference to
159 // it's Set (if it belongs to one), a reference to it's Print (if it was minted by one), a reference
160 // to it's Faucet (if it was minted by one) and has a unique serial number.
161 pub case NFT
162 }
163
164 pub let OBJECT_TYPE_MASK: UInt64
165 pub let SEQUENCE_MASK: UInt64
166
167 // Generates an ID for the given object type and sequence. We generate IDs this way
168 // so that they are unique across the various types of objects supported by this
169 // contract.
170 //
171 pub fun generateId(_ objectType: ObjectType, _ sequence: UInt64): UInt64 {
172 if (sequence > 36028797018963967) {
173 panic("sequence may only have 55 bits and must be less than 36028797018963967")
174 }
175 var ret: UInt64 = UInt64(objectType.rawValue)
176 ret = ret << UInt64(55)
177 ret = ret | ((sequence << UInt64(9)) >> UInt64(9))
178 return ret
179 }
180
181 // Extracts the ObjectType from an id
182 //
183 pub fun getObjectType(_ id: UInt64): ObjectType {
184 return ObjectType(rawValue: UInt8(id >> UInt64(55)))!
185 }
186
187 // Extracts the sequence from an id
188 //
189 pub fun getSequence(_ id: UInt64): UInt64 {
190 return id & TenantService.SEQUENCE_MASK
191 }
192
193 // Indicates whether or not the given id is for a given ObjectType.
194 //
195 pub fun isObjectType(_ id: UInt64, _ objectType: ObjectType): Bool {
196 return (TenantService.getObjectType(id) == objectType)
197 }
198
199 // Returns the tenant id that was supplied when the contract was created
200 //
201 pub fun getTenantId(): String {
202 return self.id
203 }
204
205 // Returns the version of this contract
206 //
207 pub fun getVersion(): UInt32 {
208 return 2
209 }
210
211 // TenantAdmin is used for administering the Tenant
212 //
213 pub resource TenantAdmin {
214
215 // Closes the Tenant, rendering any write access impossible
216 //
217 pub fun close() {
218 if !TenantService.closed {
219 TenantService.closed = true
220 emit TenantClosed()
221 }
222 }
223
224 // Creates a new Archetype returning it's id.
225 //
226 pub fun createArchetype(
227 name: String,
228 description: String,
229 metadata: {String: TenantService.MetadataField}
230 ): UInt64 {
231 pre {
232 TenantService.closed != true: "The Tenant is closed"
233 }
234 var archetype = Archetype(name: name, description: description, metadata: metadata)
235 TenantService.archetypes[archetype.id] = archetype
236 TenantService.archetypeAdmins[archetype.id] <-! create ArchetypeAdmin(archetype.id)
237 return archetype.id
238 }
239
240 // Grants admin access to the given Archetype
241 //
242 pub fun borrowArchetypeAdmin(_ id: UInt64): &ArchetypeAdmin? {
243 pre {
244 TenantService.closed != true: "The Tenant is closed"
245 TenantService.archetypeAdmins[id] != nil: "Archetype not found"
246 TenantService.isObjectType(id, ObjectType.ARCHETYPE): "ObjectType is not an Archetype"
247 }
248 return &TenantService.archetypeAdmins[id] as &ArchetypeAdmin?
249 }
250
251 // Creates a new Artifact returning it's id.
252 //
253 pub fun createArtifact(
254 archetypeId: UInt64,
255 name: String,
256 description: String,
257 maxMintCount: UInt64,
258 metadata: {String: TenantService.MetadataField}
259 ): UInt64 {
260 pre {
261 TenantService.closed != true: "The Tenant is closed"
262 TenantService.archetypes[archetypeId] != nil: "The Archetype wasn't found"
263 self.borrowArchetypeAdmin(archetypeId)?.closed != true: "The Archetype is closed"
264 }
265 var artifact = Artifact(archetypeId: archetypeId, name: name, description: description, maxMintCount: maxMintCount, metadata: metadata)
266 TenantService.artifacts[artifact.id] = artifact
267 TenantService.artifactAdmins[artifact.id] <-! create ArtifactAdmin(id: artifact.id)
268 TenantService.nextNftSerialNumber[artifact.id] = 1
269 return artifact.id
270 }
271
272 // Grants admin access to the given Artifact
273 //
274 pub fun borrowArtifactAdmin(_ id: UInt64): &ArtifactAdmin? {
275 pre {
276 TenantService.closed != true: "The Tenant is closed"
277 TenantService.artifactAdmins[id] != nil: "Artifact not found"
278 TenantService.isObjectType(id, ObjectType.ARTIFACT): "ObjectType is not an Artifact"
279 }
280 return &TenantService.artifactAdmins[id] as &ArtifactAdmin?
281 }
282
283 // Creates a new Set returning it's id.
284 //
285 pub fun createSet(name: String, description: String, metadata: {String: TenantService.MetadataField}): UInt64 {
286 pre {
287 TenantService.closed != true: "The Tenant is closed"
288 }
289 var set = Set(name: name, description: description, metadata: metadata)
290 TenantService.sets[set.id] = set
291 TenantService.setAdmins[set.id] <-! create SetAdmin(set.id)
292 return set.id
293 }
294
295 // Grants admin access to the given Set
296 //
297 pub fun borrowSetAdmin(_ id: UInt64): &SetAdmin? {
298 pre {
299 TenantService.closed != true: "The Tenant is closed"
300 TenantService.setAdmins[id] != nil: "Set not found"
301 TenantService.isObjectType(id, ObjectType.SET): "ObjectType is not a Set"
302 }
303 return &TenantService.setAdmins[id] as &SetAdmin?
304 }
305
306 // Creates a new Print returning it's id.
307 //
308 pub fun createPrint(
309 artifactId: UInt64,
310 setId: UInt64?,
311 name: String,
312 description: String,
313 maxMintCount: UInt64,
314 metadata: {String: TenantService.MetadataField}
315 ): UInt64 {
316 pre {
317 TenantService.closed != true: "The Tenant is closed"
318 self.borrowArtifactAdmin(artifactId)?.closed != true: "The Artifact is closed"
319 setId == nil || self.borrowSetAdmin(setId!)?.closed != true: "The Set is closed"
320 }
321 var print = Print(artifactId: artifactId, setId: setId, name: name, description: description, maxMintCount: maxMintCount, metadata: metadata)
322 TenantService.prints[print.id] = print
323 TenantService.printAdmins[print.id] <-! create PrintAdmin(print.id, print.serialNumberStart)
324 return print.id
325 }
326
327 // Grants admin access to the given Print
328 //
329 pub fun borrowPrintAdmin(_ id: UInt64): &PrintAdmin? {
330 pre {
331 TenantService.closed != true: "The Tenant is closed"
332 TenantService.printAdmins[id] != nil: "Print not found"
333 TenantService.isObjectType(id, ObjectType.PRINT): "ObjectType is not a print"
334 }
335 return &TenantService.printAdmins[id] as &PrintAdmin?
336 }
337
338 // Creates a new Faucet returning it's id.
339 //
340 pub fun createFaucet(
341 artifactId: UInt64,
342 setId: UInt64?,
343 name: String,
344 description: String,
345 maxMintCount: UInt64,
346 metadata: {String: TenantService.MetadataField}
347 ): UInt64 {
348 pre {
349 TenantService.closed != true: "The Tenant is closed"
350 self.borrowArtifactAdmin(artifactId)?.closed != true: "The Artifact is closed"
351 setId == nil || self.borrowSetAdmin(setId!)?.closed != true: "The Set is closed"
352 }
353 var faucet = Faucet(artifactId: artifactId, setId: setId, name: name, description: description, maxMintCount: maxMintCount, metadata: metadata)
354 TenantService.faucets[faucet.id] = faucet
355 TenantService.faucetAdmins[faucet.id] <-! create FaucetAdmin(id: faucet.id)
356 return faucet.id
357 }
358
359 // Grants admin access to the given Faucet
360 //
361 pub fun borrowFaucetAdmin(_ id: UInt64): &FaucetAdmin? {
362 pre {
363 TenantService.closed != true: "The Tenant is closed"
364 TenantService.faucetAdmins[id] != nil: "Faucet not found"
365 TenantService.isObjectType(id, ObjectType.FAUCET): "ObjectType is not a faucet"
366 }
367 return &TenantService.faucetAdmins[id] as &FaucetAdmin?
368 }
369
370 // Mints an NFT
371 //
372 pub fun mintNFT(artifactId: UInt64, printId: UInt64?, faucetId: UInt64?, setId: UInt64?, metadata: {String: TenantService.MetadataField}): @NFT {
373 pre {
374 TenantService.artifacts[artifactId] != nil: "Cannot mint the NFT: The Artifact wasn't found"
375 self.borrowArtifactAdmin(artifactId)?.closed != true: "The Artifact is closed"
376
377 printId == nil || TenantService.isObjectType(printId!, ObjectType.PRINT): "Id supplied for printId is not an ObjectType of print"
378 faucetId == nil || TenantService.isObjectType(faucetId!, ObjectType.FAUCET): "Id supplied for faucetId is not an ObjectType of faucet"
379 setId == nil || TenantService.isObjectType(setId!, ObjectType.SET): "Id supplied for setId is not an ObjectType of set"
380
381 printId == nil || TenantService.prints[printId!] != nil: "Cannot mint the NFT: The Print wasn't found"
382 faucetId == nil || TenantService.faucets[faucetId!] != nil: "Cannot mint the NFT: The Faucet wasn't found"
383 setId == nil || TenantService.sets[setId!] != nil: "Cannot mint the NFT: The Set wasn't found"
384
385 printId == nil || self.borrowPrintAdmin(printId!)?.closed != true: "The Print is closed"
386 faucetId == nil || self.borrowFaucetAdmin(faucetId!)?.closed != true: "The Faucet is closed"
387 setId == nil || self.borrowSetAdmin(setId!)?.closed != true: "The Set is closed"
388
389 faucetId == nil || TenantService.faucets[faucetId!]!.artifactId == artifactId: "The artifactId doesn't match the Faucet's artifactId"
390 printId == nil || TenantService.prints[printId!]!.artifactId == artifactId: "The artifactId doesn't match the Print's artifactId"
391
392 faucetId == nil || TenantService.faucets[faucetId!]!.setId == setId: "The setId doesn't match the Faucet's setId"
393 printId == nil || TenantService.prints[printId!]!.setId == setId: "The setId doesn't match the Print's setId"
394
395 !(faucetId != nil && printId != nil): "Can only mint from one of a faucet or print"
396 }
397
398 let artifact: Artifact = TenantService.artifacts[artifactId]!
399 let artifactAdmin = self.borrowArtifactAdmin(artifactId)!
400 artifactAdmin.logMint(1)
401 if printId != nil {
402 artifactAdmin.logPrint(1)
403 }
404
405 let archetype: Archetype = TenantService.archetypes[artifact.archetypeId]!
406 let archetypeAdmin = self.borrowArchetypeAdmin(artifact.archetypeId)!
407 if archetypeAdmin != nil {
408 archetypeAdmin.logMint(1)
409 if printId != nil {
410 archetypeAdmin.logPrint(1)
411 }
412 }
413
414 if faucetId != nil {
415 let faucetAdmin = self.borrowFaucetAdmin(faucetId!)!
416 faucetAdmin.logMint(1)
417 }
418
419 if setId != nil {
420 let setAdmin = self.borrowSetAdmin(setId!)!
421 setAdmin.logMint(1)
422 if printId != nil {
423 setAdmin.logPrint(1)
424 }
425 }
426
427 if printId != nil {
428 let printAdmin = self.borrowPrintAdmin(printId!)!
429 printAdmin.logMint(1)
430 }
431
432 let newNFT: @NFT <- create NFT(
433 archetypeId: artifact.archetypeId,
434 artifactId: artifact.id,
435 printId: printId,
436 faucetId: faucetId,
437 setId: setId,
438 metadata: metadata)
439
440 return <- newNFT
441 }
442
443 // Mints many NFTs
444 //
445 pub fun batchMintNFTs(
446 count: UInt64,
447 artifactId: UInt64,
448 printId: UInt64?,
449 faucetId: UInt64?,
450 setId: UInt64?,
451 metadata: {String: TenantService.MetadataField}
452 ): @Collection {
453 let newCollection <- create Collection()
454 var i: UInt64 = 0
455 while i < count {
456 newCollection.deposit(token: <-self.mintNFT(
457 artifactId: artifactId,
458 printId: printId,
459 faucetId: faucetId,
460 setId: setId,
461 metadata: metadata
462 ))
463 i = i + (1 as UInt64)
464 }
465 return <- newCollection
466 }
467
468 // Creates a new TenantAdmin that allows for another account
469 // to administer the Tenant
470 //
471 pub fun createNewTenantAdmin(): @TenantAdmin {
472 return <- create TenantAdmin()
473 }
474 }
475
476 // =====================================
477 // Archetype
478 // =====================================
479
480 pub event ArchetypeCreated(_ id: UInt64)
481 pub event ArchetypeDestroyed(_ id: UInt64)
482 pub event ArchetypeClosed(_ id: UInt64)
483
484 pub fun getArchetype(_ id: UInt64): Archetype? {
485 pre {
486 TenantService.isObjectType(id, ObjectType.ARCHETYPE): "Id supplied is not for an archetype"
487 }
488 return TenantService.archetypes[id]
489 }
490
491 pub fun getArchetypeView(_ id: UInt64): ArchetypeView? {
492 pre {
493 TenantService.isObjectType(id, ObjectType.ARCHETYPE): "Id supplied is not for an archetype"
494 }
495 if TenantService.archetypes[id] == nil {
496 return nil
497 }
498 let archetype = TenantService.archetypes[id]!
499 let archetypeAdmin = (&TenantService.archetypeAdmins[id] as &ArchetypeAdmin?)!
500 return ArchetypeView(
501 id: archetype.id,
502 name: archetype.name,
503 description: archetype.description,
504 metadata: archetype.metadata,
505 mintCount: archetypeAdmin.mintCount,
506 printCount: archetypeAdmin.printCount,
507 closed: archetypeAdmin.closed
508 )
509 }
510
511 pub fun getArchetypeViews(_ archetypes: [UInt64]): [ArchetypeView] {
512 let ret: [ArchetypeView] = []
513 for archetype in archetypes {
514 let element = self.getArchetypeView(archetype)
515 if element != nil {
516 ret.append(element!)
517 }
518 }
519 return ret
520 }
521
522 pub fun getAllArchetypes(): [Archetype] {
523 return TenantService.archetypes.values
524 }
525
526 // The immutable data for an Archetype
527 //
528 pub struct Archetype {
529 pub let id: UInt64
530 pub let name: String
531 pub let description: String
532 pub let metadata: {String: TenantService.MetadataField}
533
534 init(name: String, description: String, metadata: {String: TenantService.MetadataField}) {
535 self.id = TenantService.generateId(ObjectType.ARCHETYPE, TenantService.archetypeSeq)
536 self.name = name
537 self.description = description
538 self.metadata = metadata
539 TenantService.archetypeSeq = TenantService.archetypeSeq + 1 as UInt64
540 emit ArchetypeCreated(self.id)
541 }
542 }
543
544 // The mutable data for an Archetype
545 //
546 pub resource ArchetypeAdmin {
547
548 pub let id: UInt64
549 pub var mintCount: UInt64
550 pub var printCount: UInt64
551 pub var closed: Bool
552
553 init(_ id: UInt64) {
554 self.id = id
555 self.mintCount = 0
556 self.printCount = 0
557 self.closed = false
558 }
559
560 pub fun close() {
561 if !self.closed {
562 self.closed = true
563 emit ArchetypeClosed(self.id)
564 }
565 }
566
567 pub fun logMint(_ count: UInt64) {
568 pre {
569 TenantService.closed != true: "The Tenant is closed"
570 self.closed != true: "The Archetype is closed"
571 }
572 self.mintCount = self.mintCount + count
573 }
574
575 pub fun logPrint(_ count: UInt64) {
576 pre {
577 TenantService.closed != true: "The Tenant is closed"
578 self.closed != true: "The Archetype is closed"
579 }
580 self.printCount = self.printCount + count
581 }
582
583 destroy() {
584 emit ArchetypeDestroyed(self.id)
585 }
586 }
587
588 // An immutable view for an Archetype and all of it's data
589 //
590 pub struct ArchetypeView {
591 pub let id: UInt64
592 pub let name: String
593 pub let description: String
594 pub let metadata: {String: TenantService.MetadataField}
595 pub let mintCount: UInt64
596 pub let printCount: UInt64
597 pub let closed: Bool
598
599 init(
600 id: UInt64,
601 name: String,
602 description: String,
603 metadata: {String: TenantService.MetadataField},
604 mintCount: UInt64,
605 printCount: UInt64,
606 closed: Bool
607 ) {
608 self.id = id
609 self.name = name
610 self.description = description
611 self.metadata = metadata
612 self.mintCount = mintCount
613 self.printCount = printCount
614 self.closed = closed
615 }
616 }
617
618 // =====================================
619 // Artifact
620 // =====================================
621
622 pub event ArtifactCreated(_ id: UInt64)
623 pub event ArtifactMaxMintCountChanged(_ id: UInt64, _ oldMaxMintCount: UInt64, _ newMaxMintCount: UInt64)
624 pub event ArtifactDestroyed(_ id: UInt64)
625 pub event ArtifactClosed(_ id: UInt64)
626
627 pub fun getArtifact(_ id: UInt64): Artifact? {
628 pre {
629 TenantService.isObjectType(id, ObjectType.ARTIFACT): "Id supplied is not for an artifact"
630 }
631 return TenantService.artifacts[id]
632 }
633
634 pub fun getArtifactView(_ id: UInt64): ArtifactView? {
635 pre {
636 TenantService.isObjectType(id, ObjectType.ARTIFACT): "Id supplied is not for an artifact"
637 }
638 if TenantService.artifacts[id] == nil {
639 return nil
640 }
641 let artifact = TenantService.artifacts[id]!
642 let artifactAdmin = (&TenantService.artifactAdmins[id] as &ArtifactAdmin?)!
643 return ArtifactView(
644 id: artifact.id,
645 archetypeId: artifact.archetypeId,
646 name: artifact.name,
647 description: artifact.description,
648 metadata: artifact.metadata,
649 maxMintCount: artifact.maxMintCount,
650 mintCount: artifactAdmin.mintCount,
651 printCount: artifactAdmin.printCount,
652 closed: artifactAdmin.closed
653 )
654 }
655
656 pub fun getArtifactViews(_ artifacts: [UInt64]): [ArtifactView] {
657 let ret: [ArtifactView] = []
658 for artifact in artifacts {
659 let element = self.getArtifactView(artifact)
660 if element != nil {
661 ret.append(element!)
662 }
663 }
664 return ret
665 }
666
667 pub fun getAllArtifacts(): [Artifact] {
668 return TenantService.artifacts.values
669 }
670
671 pub fun getArtifactsBySet(_ setId: UInt64): [UInt64] {
672 let map = TenantService.artifactsBySet[setId]
673 if map != nil {
674 return map!.keys
675 }
676 return []
677 }
678
679 pub fun getFaucetsBySet(_ setId: UInt64): [UInt64] {
680 let map = TenantService.faucetsBySet[setId]
681 if map != nil {
682 return map!.keys
683 }
684 return []
685 }
686
687 pub fun getSetsByArtifact(_ artifactId: UInt64): [UInt64] {
688 let map = TenantService.setsByArtifact[artifactId]
689 if map != nil {
690 return map!.keys
691 }
692 return []
693 }
694
695 pub fun getFaucetsByArtifact(_ artifactId: UInt64): [UInt64] {
696 let map = TenantService.faucetsByArtifact[artifactId]
697 if map != nil {
698 return map!.keys
699 }
700 return []
701 }
702
703 pub fun getArtifactsByArchetype(_ archetypeId: UInt64): [UInt64] {
704 let map = TenantService.artifactsByArchetype[archetypeId]
705 if map != nil {
706 return map!.keys
707 }
708 return []
709 }
710
711 // The immutable data for an Artifact
712 //
713 pub struct Artifact {
714 pub let id: UInt64
715 pub let archetypeId: UInt64
716 pub let name: String
717 pub let description: String
718 pub let maxMintCount: UInt64
719 pub let metadata: {String: TenantService.MetadataField}
720
721 init(archetypeId: UInt64, name: String, description: String, maxMintCount: UInt64, metadata: {String: TenantService.MetadataField}) {
722 self.id = TenantService.generateId(ObjectType.ARTIFACT, TenantService.artifactSeq)
723 self.archetypeId = archetypeId
724 self.name = name
725 self.description = description
726 self.maxMintCount = maxMintCount
727 self.metadata = metadata
728 TenantService.artifactSeq = TenantService.artifactSeq + 1 as UInt64
729 emit ArtifactCreated(self.id)
730 }
731 }
732
733 // The mutable data for an Artifact
734 //
735 pub resource ArtifactAdmin {
736
737 pub let id: UInt64
738 pub var mintCount: UInt64
739 pub var printCount: UInt64
740 pub var closed: Bool
741
742 init(id: UInt64) {
743 self.id = id
744 self.mintCount = 0
745 self.printCount = 0
746 self.closed = false
747 }
748
749 pub fun close() {
750 if !self.closed {
751 self.closed = true
752 emit ArtifactClosed(self.id)
753 }
754 }
755
756 pub fun logMint(_ count: UInt64) {
757 pre {
758 TenantService.closed != true: "The Tenant is closed"
759 self.closed != true: "The Artifact is closed"
760 ((TenantService.artifacts[self.id]!.maxMintCount == (0 as UInt64))
761 || (TenantService.artifacts[self.id]!.maxMintCount >= (self.mintCount + count))): "The Artifact would exceed it's maxMintCount"
762 }
763 self.mintCount = self.mintCount + count
764 }
765
766 pub fun logPrint(_ count: UInt64) {
767 pre {
768 TenantService.closed != true: "The Tenant is closed"
769 self.closed != true: "The Artifact is closed"
770 }
771 self.printCount = self.printCount + count
772 }
773
774 destroy() {
775 emit ArtifactDestroyed(self.id)
776 }
777 }
778
779 // An immutable view for an Artifact and all of it's data
780 //
781 pub struct ArtifactView {
782 pub let id: UInt64
783 pub let archetypeId: UInt64
784 pub let name: String
785 pub let description: String
786 pub let metadata: {String: TenantService.MetadataField}
787 pub let maxMintCount: UInt64
788 pub let mintCount: UInt64
789 pub let printCount: UInt64
790 pub let closed: Bool
791
792 init(
793 id: UInt64,
794 archetypeId: UInt64,
795 name: String,
796 description: String,
797 metadata: {String: TenantService.MetadataField},
798 maxMintCount: UInt64,
799 mintCount: UInt64,
800 printCount: UInt64,
801 closed: Bool
802 ) {
803 self.id = id
804 self.archetypeId = archetypeId
805 self.name = name
806 self.description = description
807 self.metadata = metadata
808 self.maxMintCount = maxMintCount
809 self.mintCount = mintCount
810 self.printCount = printCount
811 self.closed = closed
812 }
813 }
814
815 // =====================================
816 // Set
817 // =====================================
818
819 pub event SetCreated(_ id: UInt64)
820 pub event SetDestroyed(_ id: UInt64)
821 pub event SetClosed(_ id: UInt64)
822
823 pub fun getSet(_ id: UInt64): Set? {
824 pre {
825 TenantService.isObjectType(id, ObjectType.SET): "Id supplied is not for an set"
826 }
827 return TenantService.sets[id]
828 }
829
830 pub fun getSetView(_ id: UInt64): SetView? {
831 pre {
832 TenantService.isObjectType(id, ObjectType.SET): "Id supplied is not for an set"
833 }
834 if TenantService.sets[id] == nil {
835 return nil
836 }
837 let set = TenantService.sets[id]!
838 let setAdmin = (&TenantService.setAdmins[id] as &SetAdmin?)!
839 return SetView(
840 id: set.id,
841 name: set.name,
842 description: set.description,
843 metadata: set.metadata,
844 mintCount: setAdmin.mintCount,
845 printCount: setAdmin.printCount,
846 closed: setAdmin.closed
847 )
848 }
849
850 pub fun getSetViews(_ sets: [UInt64]): [SetView] {
851 let ret: [SetView] = []
852 for set in sets {
853 let element = self.getSetView(set)
854 if element != nil {
855 ret.append(element!)
856 }
857 }
858 return ret
859 }
860
861 pub fun getAllSets(): [Set] {
862 return TenantService.sets.values
863 }
864
865 // The immutable data for an Set
866 //
867 pub struct Set {
868 pub let id: UInt64
869 pub let name: String
870 pub let description: String
871 pub let metadata: {String: TenantService.MetadataField}
872
873 init(
874 name: String,
875 description: String,
876 metadata: {String: TenantService.MetadataField}
877 ) {
878 self.id = TenantService.generateId(ObjectType.SET, TenantService.setSeq)
879 self.name = name
880 self.description = description
881 self.metadata = metadata
882 TenantService.setSeq = TenantService.setSeq + 1 as UInt64
883 TenantService.faucetsBySet[self.id] = {}
884 emit SetCreated(self.id)
885 }
886 }
887
888 // The mutable data for an Set
889 //
890 pub resource SetAdmin {
891 pub let id: UInt64
892 pub var mintCount: UInt64
893 pub var printCount: UInt64
894 pub var closed: Bool
895
896 init(_ id: UInt64) {
897 self.id = id
898 self.mintCount = 0
899 self.printCount = 0
900 self.closed = false
901 }
902
903 pub fun close() {
904 if !self.closed {
905 self.closed = true
906 emit SetClosed(self.id)
907 }
908 }
909
910 pub fun logMint(_ count: UInt64) {
911 pre {
912 TenantService.closed != true: "The Tenant is closed"
913 self.closed != true: "The Set is closed"
914 }
915 self.mintCount = self.mintCount + count
916 }
917
918 pub fun logPrint(_ count: UInt64) {
919 pre {
920 TenantService.closed != true: "The Tenant is closed"
921 self.closed != true: "The Set is closed"
922 }
923 self.printCount = self.printCount + count
924 }
925
926 destroy() {
927 emit SetDestroyed(self.id)
928 }
929 }
930
931 // An immutable view for an Set and all of it's data
932 //
933 pub struct SetView {
934 pub let id: UInt64
935 pub let name: String
936 pub let description: String
937 pub let metadata: {String: TenantService.MetadataField}
938 pub let mintCount: UInt64
939 pub let printCount: UInt64
940 pub let closed: Bool
941
942 init(
943 id: UInt64,
944 name: String,
945 description: String,
946 metadata: {String: TenantService.MetadataField},
947 mintCount: UInt64,
948 printCount: UInt64,
949 closed: Bool
950 ) {
951 self.id = id
952 self.name = name
953 self.description = description
954 self.metadata = metadata
955 self.mintCount = mintCount
956 self.printCount = printCount
957 self.closed = closed
958 }
959 }
960
961 // =====================================
962 // Print
963 // =====================================
964
965 pub event PrintCreated(_ id: UInt64)
966 pub event PrintDestroyed(_ id: UInt64)
967 pub event PrintClosed(_ id: UInt64)
968
969 pub fun getPrint(_ id: UInt64): Print? {
970 pre {
971 TenantService.isObjectType(id, ObjectType.PRINT): "Id supplied is not for a print"
972 }
973 return TenantService.prints[id]
974 }
975
976 pub fun getPrintView(_ id: UInt64): PrintView? {
977 pre {
978 TenantService.isObjectType(id, ObjectType.PRINT): "Id supplied is not for a print"
979 }
980 if TenantService.prints[id] == nil {
981 return nil
982 }
983 let print = TenantService.prints[id]!
984 let printAdmin = (&TenantService.printAdmins[id] as &PrintAdmin?)!
985 return PrintView(
986 id: print.id,
987 artifactId: print.artifactId,
988 setId: print.setId,
989 name: print.name,
990 description: print.description,
991 maxMintCount: print.maxMintCount,
992 metadata: print.metadata,
993 serialNumberStart: print.serialNumberStart,
994 nextNftSerialNumber: printAdmin.nextNftSerialNumber,
995 mintCount: printAdmin.mintCount,
996 closed: printAdmin.closed
997 )
998 }
999
1000 pub fun getPrintViews(_ prints: [UInt64]): [PrintView] {
1001 let ret: [PrintView] = []
1002 for print in prints {
1003 let element = self.getPrintView(print)
1004 if element != nil {
1005 ret.append(element!)
1006 }
1007 }
1008 return ret
1009 }
1010
1011 pub fun getAllPrints(): [Print] {
1012 return TenantService.prints.values
1013 }
1014
1015 // The immutable data for an Print
1016 //
1017 pub struct Print {
1018 pub let id: UInt64
1019 pub let artifactId: UInt64
1020 pub let setId: UInt64?
1021 pub let name: String
1022 pub let description: String
1023 pub let maxMintCount: UInt64
1024 pub let metadata: {String: TenantService.MetadataField}
1025 pub let serialNumberStart: UInt64
1026
1027 init(
1028 artifactId: UInt64,
1029 setId: UInt64?,
1030 name: String,
1031 description: String,
1032 maxMintCount: UInt64,
1033 metadata: {String: TenantService.MetadataField}
1034 ) {
1035 pre {
1036 maxMintCount > 0 : "maxMintCount must be greater than 0"
1037 }
1038 self.id = TenantService.generateId(ObjectType.PRINT, TenantService.printSeq)
1039 self.artifactId = artifactId
1040 self.setId = setId
1041 self.name = name
1042 self.description = description
1043 self.maxMintCount = maxMintCount
1044 self.metadata = metadata
1045 self.serialNumberStart = TenantService.nextNftSerialNumber[artifactId]!
1046 TenantService.nextNftSerialNumber[artifactId] = self.serialNumberStart + maxMintCount
1047 TenantService.printSeq = TenantService.printSeq + 1 as UInt64
1048 emit PrintCreated(self.id)
1049 }
1050 }
1051
1052 // The mutable data for an Print
1053 //
1054 pub resource PrintAdmin {
1055
1056 pub let id: UInt64
1057 pub var nextNftSerialNumber: UInt64
1058 pub var mintCount: UInt64
1059 pub var closed: Bool
1060
1061 init(_ id: UInt64, _ serialNumberStart: UInt64) {
1062 self.id = id
1063 self.mintCount = 0
1064 self.closed = false
1065 self.nextNftSerialNumber = serialNumberStart
1066 }
1067
1068 pub fun close() {
1069 if !self.closed {
1070 self.closed = true
1071 emit PrintClosed(self.id)
1072 }
1073 }
1074
1075 pub fun getAndIncrementSerialNumber(): UInt64 {
1076 let ret: UInt64 = self.nextNftSerialNumber
1077 self.nextNftSerialNumber = ret + (1 as UInt64)
1078 return ret
1079 }
1080
1081 pub fun logMint(_ count: UInt64) {
1082 pre {
1083 TenantService.closed != true: "The Tenant is closed"
1084 self.closed != true: "The Print is closed"
1085 TenantService.prints[self.id]!.maxMintCount >= (self.mintCount + count): "The Print would exceed it's maxMintCount"
1086 }
1087 self.mintCount = self.mintCount + count
1088 }
1089
1090 destroy() {
1091 emit PrintDestroyed(self.id)
1092 }
1093 }
1094
1095 // An immutable view for an Print and all of it's data
1096 //
1097 pub struct PrintView {
1098 pub let id: UInt64
1099 pub let artifactId: UInt64
1100 pub let setId: UInt64?
1101 pub let name: String
1102 pub let description: String
1103 pub let maxMintCount: UInt64
1104 pub let metadata: {String: TenantService.MetadataField}
1105 pub let serialNumberStart: UInt64
1106 pub let nextNftSerialNumber: UInt64
1107 pub let mintCount: UInt64
1108 pub let closed: Bool
1109
1110 init(
1111 id: UInt64,
1112 artifactId: UInt64,
1113 setId: UInt64?,
1114 name: String,
1115 description: String,
1116 maxMintCount: UInt64,
1117 metadata: {String: TenantService.MetadataField},
1118 serialNumberStart: UInt64,
1119 nextNftSerialNumber: UInt64,
1120 mintCount: UInt64,
1121 closed: Bool
1122 ) {
1123 self.id = id
1124 self.artifactId = artifactId
1125 self.setId = setId
1126 self.name = name
1127 self.description = description
1128 self.maxMintCount = maxMintCount
1129 self.metadata = metadata
1130 self.serialNumberStart = serialNumberStart
1131 self.nextNftSerialNumber = nextNftSerialNumber
1132 self.mintCount = mintCount
1133 self.closed = closed
1134 }
1135 }
1136
1137 // =====================================
1138 // Faucet
1139 // =====================================
1140
1141 pub event FaucetCreated(_ id: UInt64)
1142 pub event FaucetMaxMintCountChanged(_ id: UInt64, _ oldMaxMintCount: UInt64, _ newMaxMintCount: UInt64)
1143 pub event FaucetDestroyed(_ id: UInt64)
1144 pub event FaucetClosed(_ id: UInt64)
1145
1146 pub fun getFaucet(_ id: UInt64): Faucet? {
1147 pre {
1148 TenantService.isObjectType(id, ObjectType.FAUCET): "Id supplied is not for a faucet"
1149 }
1150 return TenantService.faucets[id]
1151 }
1152
1153 pub fun getFaucetView(_ id: UInt64): FaucetView? {
1154 pre {
1155 TenantService.isObjectType(id, ObjectType.FAUCET): "Id supplied is not for a faucet"
1156 }
1157 if TenantService.faucets[id] == nil {
1158 return nil
1159 }
1160 let faucet = TenantService.faucets[id]!
1161 let faucetAdmin = (&TenantService.faucetAdmins[id] as &FaucetAdmin?)!
1162 return FaucetView(
1163 id: faucet.id,
1164 artifactId: faucet.artifactId,
1165 setId: faucet.setId,
1166 name: faucet.name,
1167 description: faucet.description,
1168 maxMintCount: faucet.maxMintCount,
1169 metadata: faucet.metadata,
1170 mintCount: faucetAdmin.mintCount,
1171 closed: faucetAdmin.closed
1172 )
1173 }
1174
1175 pub fun getFaucetViews(_ faucets: [UInt64]): [FaucetView] {
1176 let ret: [FaucetView] = []
1177 for faucet in faucets {
1178 let element = self.getFaucetView(faucet)
1179 if element != nil {
1180 ret.append(element!)
1181 }
1182 }
1183 return ret
1184 }
1185
1186 pub fun getAllFaucets(): [Faucet] {
1187 return TenantService.faucets.values
1188 }
1189
1190 // The immutable data for an Faucet
1191 //
1192 pub struct Faucet {
1193 pub let id: UInt64
1194 pub let artifactId: UInt64
1195 pub let setId: UInt64?
1196 pub let name: String
1197 pub let description: String
1198 pub let maxMintCount: UInt64
1199 pub let metadata: {String: TenantService.MetadataField}
1200
1201 init(
1202 artifactId: UInt64,
1203 setId: UInt64?,
1204 name: String,
1205 description: String,
1206 maxMintCount: UInt64,
1207 metadata: {String: TenantService.MetadataField}
1208 ) {
1209 self.id = TenantService.generateId(ObjectType.FAUCET, TenantService.faucetSeq)
1210 self.artifactId = artifactId
1211 self.setId = setId
1212 self.name = name
1213 self.description = description
1214 self.maxMintCount = maxMintCount
1215 self.metadata = metadata
1216 TenantService.faucetSeq = TenantService.faucetSeq + 1 as UInt64
1217
1218 if self.setId != nil {
1219 let faucetsBySet = TenantService.faucetsBySet[self.setId!]!
1220 faucetsBySet[self.id] = true
1221 }
1222
1223 emit FaucetCreated(self.id)
1224 }
1225 }
1226
1227 // The mutable data for an Faucet
1228 //
1229 pub resource FaucetAdmin {
1230
1231 pub let id: UInt64
1232 pub var mintCount: UInt64
1233 pub var closed: Bool
1234
1235 init(id: UInt64) {
1236 self.id = id
1237 self.mintCount = 0
1238 self.closed = false
1239 }
1240
1241 pub fun close() {
1242 if !self.closed {
1243 self.closed = true
1244 emit FaucetClosed(self.id)
1245 }
1246 }
1247
1248 pub fun logMint(_ count: UInt64) {
1249 pre {
1250 TenantService.closed != true: "The Tenant is closed"
1251 self.closed != true: "The Faucet is closed"
1252 ((TenantService.faucets[self.id]!.maxMintCount == (0 as UInt64))
1253 || (TenantService.faucets[self.id]!.maxMintCount >= (self.mintCount + count))): "The Faucet would exceed it's maxMintCount"
1254 }
1255 self.mintCount = self.mintCount + count
1256 }
1257
1258 destroy() {
1259 emit FaucetDestroyed(self.id)
1260 }
1261 }
1262
1263 // An immutable view for an Faucet and all of it's data
1264 //
1265 pub struct FaucetView {
1266 pub let id: UInt64
1267 pub let artifactId: UInt64
1268 pub let setId: UInt64?
1269 pub let name: String
1270 pub let description: String
1271 pub let maxMintCount: UInt64
1272 pub let metadata: {String: TenantService.MetadataField}
1273 pub let mintCount: UInt64
1274 pub let closed: Bool
1275
1276 init(
1277 id: UInt64,
1278 artifactId: UInt64,
1279 setId: UInt64?,
1280 name: String,
1281 description: String,
1282 maxMintCount: UInt64,
1283 metadata: {String: TenantService.MetadataField},
1284 mintCount: UInt64,
1285 closed: Bool
1286 ) {
1287 self.id = id
1288 self.artifactId = artifactId
1289 self.setId = setId
1290 self.name = name
1291 self.description = description
1292 self.maxMintCount = maxMintCount
1293 self.metadata = metadata
1294 self.mintCount = mintCount
1295 self.closed = closed
1296 }
1297 }
1298
1299 // =====================================
1300 // NFT
1301 // =====================================
1302
1303 pub event NFTCreated(_ id: UInt64)
1304 pub event NFTDestroyed(_ id: UInt64)
1305
1306 pub fun getNFTView(_ nft: &NFT): NFTView {
1307 let archetype = self.getArchetypeView(nft.archetypeId)!
1308 let artifact = self.getArtifactView(nft.artifactId)!
1309
1310 var set: SetView? = nil
1311 if nft.setId != nil {
1312 set = self.getSetView(nft.setId!)!
1313 }
1314
1315 var print: PrintView? = nil
1316 if nft.printId != nil {
1317 print = self.getPrintView(nft.printId!)!
1318 }
1319
1320 var faucet: FaucetView? = nil
1321 if nft.faucetId != nil {
1322 faucet = self.getFaucetView(nft.faucetId!)!
1323 }
1324
1325 return NFTView(
1326 id: nft.id,
1327 archetype: archetype,
1328 artifact: artifact,
1329 print: print,
1330 faucet: faucet,
1331 set: set,
1332 serialNumber: nft.serialNumber,
1333 metadata: nft.getMetadata()
1334 )
1335 }
1336
1337 pub fun getNFTViews(_ nfts: [&NFT]): [NFTView] {
1338 let ret: [NFTView] = []
1339 for nft in nfts {
1340 ret.append(self.getNFTView(nft))
1341 }
1342 return ret
1343 }
1344
1345 // The immutable data for an NFT, this is the actual NFT
1346 //
1347 pub resource NFT: NonFungibleToken.INFT {
1348 pub let id: UInt64
1349 pub let archetypeId: UInt64
1350 pub let artifactId: UInt64
1351 pub let printId: UInt64?
1352 pub let faucetId: UInt64?
1353 pub let setId: UInt64?
1354 pub let serialNumber: UInt64
1355 access(self) let metadata: {String: TenantService.MetadataField}
1356
1357 init(
1358 archetypeId: UInt64,
1359 artifactId: UInt64,
1360 printId: UInt64?,
1361 faucetId: UInt64?,
1362 setId: UInt64?,
1363 metadata: {String: TenantService.MetadataField}
1364 ) {
1365 self.id = TenantService.generateId(ObjectType.NFT, TenantService.totalSupply)
1366 self.archetypeId = archetypeId
1367 self.artifactId = artifactId
1368 self.printId = printId
1369 self.faucetId = faucetId
1370 self.setId = setId
1371 self.metadata = metadata
1372
1373 if self.printId != nil {
1374 let printAdmin = (&TenantService.printAdmins[self.printId!!] as &PrintAdmin?)!
1375 self.serialNumber = printAdmin.getAndIncrementSerialNumber()
1376
1377 } else {
1378 self.serialNumber = TenantService.nextNftSerialNumber[self.artifactId]!
1379 TenantService.nextNftSerialNumber[self.artifactId] = self.serialNumber + (1 as UInt64)
1380
1381 }
1382
1383 TenantService.totalSupply = TenantService.totalSupply + (1 as UInt64)
1384
1385 if self.setId != nil {
1386 if TenantService.setsByArtifact[self.artifactId] == nil {
1387 TenantService.setsByArtifact[self.artifactId] = {}
1388 }
1389 let setsByArtifact = TenantService.setsByArtifact[self.artifactId]!
1390 setsByArtifact[self.setId!] = true
1391
1392 if TenantService.artifactsBySet[self.setId!] == nil {
1393 TenantService.artifactsBySet[self.setId!] = {}
1394 }
1395 let artifactsBySet = TenantService.artifactsBySet[self.setId!]!
1396 artifactsBySet[self.artifactId] = true
1397 }
1398
1399 if self.faucetId != nil {
1400 if TenantService.faucetsByArtifact[self.artifactId] == nil {
1401 TenantService.faucetsByArtifact[self.artifactId] = {}
1402 }
1403 let faucetsByArtifact = TenantService.faucetsByArtifact[self.artifactId]!
1404 faucetsByArtifact[self.faucetId!] = true
1405 }
1406
1407 if TenantService.artifactsByArchetype[self.archetypeId] == nil {
1408 TenantService.artifactsByArchetype[self.archetypeId] = {}
1409 }
1410 let artifactsByArchetype = TenantService.artifactsByArchetype[self.archetypeId]!
1411 artifactsByArchetype[self.artifactId] = true
1412
1413 emit NFTCreated(self.id)
1414 }
1415
1416 pub fun getMetadata(): {String: TenantService.MetadataField} {
1417 return self.metadata
1418 }
1419
1420 destroy() {
1421 emit NFTDestroyed(self.id)
1422 }
1423 }
1424
1425 // An immutable view for an NFT and all of it's data
1426 //
1427 pub struct NFTView {
1428 pub let id: UInt64
1429 pub let archetype: ArchetypeView
1430 pub let artifact: ArtifactView
1431 pub let print: PrintView?
1432 pub let faucet: FaucetView?
1433 pub let set: SetView?
1434 pub let serialNumber: UInt64
1435 pub let metadata: {String: TenantService.MetadataField}
1436
1437 init(
1438 id: UInt64,
1439 archetype: ArchetypeView,
1440 artifact: ArtifactView,
1441 print: PrintView?,
1442 faucet: FaucetView?,
1443 set: SetView?,
1444 serialNumber: UInt64,
1445 metadata: {String: TenantService.MetadataField}
1446 ) {
1447 self.id = id
1448 self.archetype = archetype
1449 self.artifact = artifact
1450 self.print = print
1451 self.faucet = faucet
1452 self.set = set
1453 self.serialNumber = serialNumber
1454 self.metadata = metadata
1455 }
1456 }
1457
1458 // The public version of the collection that accounts can use
1459 // to deposit NFTs into other accounts
1460 //
1461 pub resource interface CollectionPublic {
1462 pub fun deposit(token: @NonFungibleToken.NFT)
1463 pub fun batchDeposit(tokens: @NonFungibleToken.Collection)
1464 pub fun getIDs(): [UInt64]
1465 pub fun borrowNFT(id: UInt64): &NonFungibleToken.NFT
1466 pub fun borrowNFTData(id: UInt64): &TenantService.NFT?
1467 pub fun borrowNFTDatas(ids: [UInt64]): [&TenantService.NFT]
1468 }
1469
1470 // The collection where NFTs are stored
1471 //
1472 pub resource Collection: CollectionPublic, NonFungibleToken.Provider, NonFungibleToken.Receiver, NonFungibleToken.CollectionPublic {
1473 pub var ownedNFTs: @{UInt64: NonFungibleToken.NFT}
1474
1475 init() {
1476 self.ownedNFTs <- {}
1477 }
1478
1479 pub fun withdraw(withdrawID: UInt64): @NonFungibleToken.NFT {
1480 let token <- self.ownedNFTs.remove(key: withdrawID)
1481 ?? panic("Cannot withdraw: NFT does not exist in the collection")
1482 emit Withdraw(id: token.id, from: self.owner?.address)
1483 return <-token
1484 }
1485
1486 pub fun batchWithdraw(ids: [UInt64]): @NonFungibleToken.Collection {
1487 var batchCollection <- create Collection()
1488 for id in ids {
1489 batchCollection.deposit(token: <-self.withdraw(withdrawID: id))
1490 }
1491 return <-batchCollection
1492 }
1493
1494 pub fun deposit(token: @NonFungibleToken.NFT) {
1495 let token <- token as! @TenantService.NFT
1496 let id = token.id
1497 let oldToken <- self.ownedNFTs[id] <- token
1498 if self.owner?.address != nil {
1499 emit Deposit(id: id, to: self.owner?.address)
1500 }
1501 destroy oldToken
1502 }
1503
1504 pub fun batchDeposit(tokens: @NonFungibleToken.Collection) {
1505 let keys = tokens.getIDs()
1506 for key in keys {
1507 self.deposit(token: <-tokens.withdraw(withdrawID: key))
1508 }
1509 destroy tokens
1510 }
1511
1512 pub fun getIDs(): [UInt64] {
1513 return self.ownedNFTs.keys
1514 }
1515
1516 pub fun borrowNFT(id: UInt64): &NonFungibleToken.NFT {
1517 pre {
1518 TenantService.isObjectType(id, ObjectType.NFT): "Id supplied is not for an nft"
1519 }
1520 return (&self.ownedNFTs[id] as &NonFungibleToken.NFT?)!
1521 }
1522
1523 pub fun borrowNFTData(id: UInt64): &TenantService.NFT? {
1524 pre {
1525 TenantService.isObjectType(id, ObjectType.NFT): "Id supplied is not for an nft"
1526 }
1527 if self.ownedNFTs[id] != nil {
1528 let ref = (&self.ownedNFTs[id] as auth &NonFungibleToken.NFT?)!
1529 return ref as! &TenantService.NFT
1530 } else {
1531 return nil
1532 }
1533 }
1534
1535 pub fun borrowNFTDatas(ids: [UInt64]): [&TenantService.NFT] {
1536 let nfts: [&TenantService.NFT] = []
1537 for id in ids {
1538 let nft = self.borrowNFTData(id: id)
1539 if nft != nil {
1540 nfts.append(nft!)
1541 }
1542 }
1543 return nfts
1544 }
1545
1546 pub fun getNFTView(id: UInt64): NFTView? {
1547 pre {
1548 TenantService.isObjectType(id, ObjectType.NFT): "Id supplied is not for an nft"
1549 }
1550 let nft = self.borrowNFTData(id: id)
1551 if nft == nil {
1552 return nil
1553 }
1554 return TenantService.getNFTView(nft!)
1555 }
1556
1557 destroy() {
1558 destroy self.ownedNFTs
1559 }
1560 }
1561
1562 pub fun createEmptyCollection(): @NonFungibleToken.Collection {
1563 return <-create TenantService.Collection()
1564 }
1565
1566 // ShardedCollection stores a dictionary of TenantService Collections
1567 // An NFT is stored in the field that corresponds to its id % numBuckets
1568 //
1569 pub resource ShardedCollection: CollectionPublic, NonFungibleToken.Provider, NonFungibleToken.Receiver, NonFungibleToken.CollectionPublic {
1570
1571 pub var collections: @{UInt64: Collection}
1572 pub let numBuckets: UInt64
1573
1574 init(numBuckets: UInt64) {
1575 self.collections <- {}
1576 self.numBuckets = numBuckets
1577 var i: UInt64 = 0
1578 while i < numBuckets {
1579 self.collections[i] <-! TenantService.createEmptyCollection() as! @Collection
1580 i = i + UInt64(1)
1581 }
1582 }
1583
1584 pub fun withdraw(withdrawID: UInt64): @NonFungibleToken.NFT {
1585 post {
1586 result.id == withdrawID: "The ID of the withdrawn NFT is incorrect"
1587 }
1588 let bucket = withdrawID % self.numBuckets
1589 let token <- self.collections[bucket]?.withdraw(withdrawID: withdrawID)!
1590 return <-token
1591 }
1592
1593 pub fun batchWithdraw(ids: [UInt64]): @NonFungibleToken.Collection {
1594 var batchCollection <- TenantService.createEmptyCollection()
1595 for id in ids {
1596 batchCollection.deposit(token: <-self.withdraw(withdrawID: id))
1597 }
1598 return <-batchCollection
1599 }
1600
1601 pub fun deposit(token: @NonFungibleToken.NFT) {
1602 let bucket = token.id % self.numBuckets
1603 let collection <- self.collections.remove(key: bucket)!
1604 collection.deposit(token: <-token)
1605 self.collections[bucket] <-! collection
1606 }
1607
1608 pub fun batchDeposit(tokens: @NonFungibleToken.Collection) {
1609 let keys = tokens.getIDs()
1610 for key in keys {
1611 self.deposit(token: <-tokens.withdraw(withdrawID: key))
1612 }
1613 destroy tokens
1614 }
1615
1616 pub fun getIDs(): [UInt64] {
1617 var ids: [UInt64] = []
1618 for key in self.collections.keys {
1619 for id in self.collections[key]?.getIDs() ?? [] {
1620 ids.append(id)
1621 }
1622 }
1623 return ids
1624 }
1625
1626 pub fun borrowNFT(id: UInt64): &NonFungibleToken.NFT {
1627 let bucket = id % self.numBuckets
1628 return self.collections[bucket]?.borrowNFT(id: id)!
1629 }
1630
1631 pub fun borrowNFTData(id: UInt64): &TenantService.NFT? {
1632 let bucket = id % self.numBuckets
1633 return self.collections[bucket]?.borrowNFTData(id: id) ?? nil
1634 }
1635
1636 pub fun borrowNFTDatas(ids: [UInt64]): [&TenantService.NFT] {
1637 let nfts: [&TenantService.NFT] = []
1638 for id in ids {
1639 let nft = self.borrowNFTData(id: id)
1640 if nft != nil {
1641 nfts.append(nft!)
1642 }
1643 }
1644 return nfts
1645 }
1646
1647 pub fun getNFTView(id: UInt64): NFTView? {
1648 let bucket = id % self.numBuckets
1649 return self.collections[bucket]?.getNFTView(id: id) ?? nil
1650 }
1651
1652 destroy() {
1653 destroy self.collections
1654 }
1655 }
1656
1657 pub fun createEmptyShardedCollection(numBuckets: UInt64): @ShardedCollection {
1658 return <-create ShardedCollection(numBuckets: numBuckets)
1659 }
1660
1661 // =====================================
1662 // Metadata
1663 // =====================================
1664
1665 // The type of a meta data field
1666 //
1667 pub enum MetadataFieldType: UInt8 {
1668 pub case STRING
1669 pub case MIME
1670 pub case NUMBER
1671 pub case BOOLEAN
1672 pub case DATE
1673 pub case DATE_TIME
1674 pub case URL
1675 pub case URL_WITH_HASH
1676 pub case GEO_POINT
1677 }
1678
1679 // a meta data field of variable type
1680 //
1681 pub struct MetadataField {
1682 pub let type: MetadataFieldType
1683 pub let value: AnyStruct
1684
1685 init(_ type: MetadataFieldType, _ value: AnyStruct) {
1686 self.type = type
1687 self.value = value
1688 }
1689
1690 pub fun getMimeValue(): Mime? {
1691 if self.type != MetadataFieldType.MIME {
1692 return nil
1693 }
1694 return self.value as? Mime
1695 }
1696
1697 pub fun getStringValue(): String? {
1698 if self.type != MetadataFieldType.STRING {
1699 return nil
1700 }
1701 return self.value as? String
1702 }
1703
1704 pub fun getNumberValue(): String? {
1705 if self.type != MetadataFieldType.NUMBER {
1706 return nil
1707 }
1708 return self.value as? String
1709 }
1710
1711 pub fun getBooleanValue(): Bool? {
1712 if self.type != MetadataFieldType.BOOLEAN {
1713 return nil
1714 }
1715 return self.value as? Bool
1716 }
1717
1718 pub fun getURLValue(): String? {
1719 if self.type != MetadataFieldType.URL {
1720 return nil
1721 }
1722 return self.value as? String
1723 }
1724
1725 pub fun getDateValue(): String? {
1726 if self.type != MetadataFieldType.DATE {
1727 return nil
1728 }
1729 return self.value as? String
1730 }
1731
1732 pub fun getDateTimeValue(): String? {
1733 if self.type != MetadataFieldType.DATE_TIME {
1734 return nil
1735 }
1736 return self.value as? String
1737 }
1738
1739 pub fun getURLWithHashValue(): URLWithHash? {
1740 if self.type != MetadataFieldType.URL_WITH_HASH {
1741 return nil
1742 }
1743 return self.value as? URLWithHash
1744 }
1745
1746 pub fun getGeoPointValue(): GeoPoint? {
1747 if self.type != MetadataFieldType.GEO_POINT {
1748 return nil
1749 }
1750 return self.value as? GeoPoint
1751 }
1752 }
1753
1754 // A url with a hash of the contents found at the url
1755 //
1756 pub struct URLWithHash {
1757 pub let url: String
1758 pub let hash: String?
1759 pub let hashAlgo: String?
1760 init(_ url: String, _ hash: String, _ hashAlgo: String?) {
1761 self.url = url
1762 self.hash = hash
1763 self.hashAlgo = hashAlgo
1764 }
1765 }
1766
1767 // A geo point without any specific projection
1768 //
1769 pub struct GeoPoint {
1770 pub let lat: UFix64
1771 pub let lng: UFix64
1772 init(_ lat: UFix64, _ lng: UFix64) {
1773 self.lat = lat
1774 self.lng = lng
1775 }
1776 }
1777
1778 // A piece of Mime content
1779 //
1780 pub struct Mime {
1781 pub let type: String
1782 pub let bytes: [UInt8]
1783 init(_ type: String, _ bytes: [UInt8]) {
1784 self.type = type
1785 self.bytes = bytes
1786 }
1787 }
1788}
1789