Smart Contract
CricketMomentsShardedCollection
A.4eded0de73020ca5.CricketMomentsShardedCollection
1// SPDX-License-Identifier: UNLICENSED
2
3/*
4 Description: Central Collection for a large number of CricketMoments
5 NFTs
6
7 This contract bundles together a bunch of Collection objects
8 in a dictionary, and then distributes the individual Moments between them
9 while implementing the same public interface
10 as the default CricketMomentCollection implementation.
11
12 If we assume that Moment IDs are uniformly distributed,
13 a ShardedCollection with 10 inner Collections should be able
14 to store 10x as many Moments (or ~1M).
15
16 When Cadence is updated to allow larger dictionaries,
17 then this contract can be retired.
18
19*/
20import NonFungibleToken from 0x1d7e57aa55817448
21import CricketMoments from 0x4eded0de73020ca5
22
23access(all) contract CricketMomentsShardedCollection {
24
25 access(all) let ShardedCollectionStoragePath: StoragePath
26
27 // ShardedCollection stores a dictionary of CricketMoments Collections
28 // A Moment is stored in the field that corresponds to its id % numBuckets
29 access(all) resource ShardedCollection: CricketMoments.CricketMomentsCollectionPublic, NonFungibleToken.CollectionPublic, NonFungibleToken.Provider, NonFungibleToken.Receiver {
30
31 // Dictionary of CricketMoments collections
32 access(all) var collections: @{UInt64: CricketMoments.Collection}
33
34 access(all) fun forEachID(_ f: fun (UInt64): Bool): Void {
35 for key in self.collections.keys {
36 let col = &self.collections[key] as &CricketMoments.Collection?
37 col?.forEachID(f)
38 }
39 }
40
41 // The number of buckets to split Moments into
42 // This makes storage more efficient and performant
43 access(all) let numBuckets: UInt64
44
45 init(numBuckets: UInt64) {
46 self.collections <- {}
47 self.numBuckets = numBuckets
48
49 // Create a new empty collection for each bucket
50 var i: UInt64 = 0
51 while i < numBuckets {
52
53 self.collections[i] <-! CricketMoments.createEmptyCollection(nftType: Type<@CricketMoments.NFT>()) as! @CricketMoments.Collection
54
55 i = i + 1 as UInt64
56 }
57 }
58
59 // withdraw removes a Moment from one of the Collections
60 // and moves it to the caller
61 access(NonFungibleToken.Withdraw) fun withdraw(withdrawID: UInt64): @{NonFungibleToken.NFT} {
62 post {
63 result.id == withdrawID: "The ID of the withdrawn NFT is incorrect"
64 }
65 // Find the bucket it should be withdrawn from
66 let bucket = withdrawID % self.numBuckets
67
68 // Withdraw the moment
69 let token <- self.collections[bucket]?.withdraw(withdrawID: withdrawID)!
70
71 return <-token
72 }
73
74 // deposit takes a Moment and adds it to the Collections dictionary
75 access(all) fun deposit(token: @{NonFungibleToken.NFT}) {
76
77 // Find the bucket this corresponds to
78 let bucket = token.id % self.numBuckets
79
80 // Get collection Reference
81 let collectionRef = (&self.collections[bucket] as &CricketMoments.Collection?)!
82
83 // Deposit the nft into the bucket
84 collectionRef.deposit(token: <-token)
85
86 }
87
88 // getIDs returns an array of the IDs that are in the Collection
89 access(all) view fun getIDs(): [UInt64] {
90
91 var ids: [UInt64] = []
92 // Concatenate IDs in all the Collections
93 for key in self.collections.keys {
94 let collectionIDs = self.collections[key]?.getIDs() ?? []
95 ids = ids.concat(collectionIDs)
96 }
97 return ids
98 }
99
100 // borrowNFT Returns a borrowed reference to a Moment in the Collection
101 // so that the caller can read data and call methods from it
102 access(all) view fun borrowNFT(_ id: UInt64): &{NonFungibleToken.NFT}? {
103 post {
104 result?.id == id: "The ID of the reference is incorrect"
105 }
106
107 // Get the bucket of the nft to be borrowed
108 let bucket = id % self.numBuckets
109
110 // Find NFT in the collections and borrow a reference
111 return self.collections[bucket]?.borrowNFT(id)!
112 }
113
114
115 // borrowCricketMoment Returns a borrowed reference to a Moment in the Collection
116 // so that the caller can read data and call methods from it
117 // They can use this to read its serial, momentId, metadata
118 //
119 // Parameters: id: The ID of the NFT to get the reference for
120 //
121 // Returns: A reference to the NFT
122 access(all) view fun borrowCricketMoment(id: UInt64): &CricketMoments.NFT? {
123
124 // Get the bucket of the nft to be borrowed
125 let bucket = id % self.numBuckets
126
127 return self.collections[bucket]?.borrowCricketMoment(id: id) ?? nil
128 }
129
130 /// getSupportedNFTTypes returns a list of NFT types that this receiver accepts
131 access(all) view fun getSupportedNFTTypes(): {Type: Bool} {
132 let supportedTypes: {Type: Bool} = {}
133 supportedTypes[Type<@CricketMoments.NFT>()] = true
134 return supportedTypes
135 }
136
137 /// Returns whether or not the given type is accepted by the collection
138 /// A collection that can accept any type should just return true by default
139 access(all) view fun isSupportedNFTType(type: Type): Bool {
140 return type == Type<@CricketMoments.NFT>()
141 }
142
143 // Return the amount of NFTs stored in the collection
144 access(all) view fun getLength(): Int {
145 return self.getIDs().length
146 }
147 }
148
149 // Creates an empty ShardedCollection and returns it to the caller
150 access(all) fun createEmptyCollection(numBuckets: UInt64): @ShardedCollection {
151 return <-create ShardedCollection(numBuckets: numBuckets)
152 }
153
154 init() {
155 self.ShardedCollectionStoragePath = /storage/CricketMomentsShardedCollection
156 }
157}
158