Smart Contract
Basketballs
A.eee6bdee2b2bdfc8.Basketballs
1import NonFungibleToken from 0x1d7e57aa55817448
2
3// Basketballs
4// NFT basketballs!
5//
6access(all) contract Basketballs: NonFungibleToken {
7
8 // Events
9 access(all) event ContractInitialized()
10 access(all) event EditionCreated(editionID: UInt32, name: String, description: String, imageURL: String)
11 access(all) event BasketballMinted(id: UInt64, editionID: UInt32, serialNumber: UInt64)
12 access(all) event Withdraw(id: UInt64, from: Address?)
13 access(all) event Deposit(id: UInt64, to: Address?)
14 access(all) event Destroy(id: UInt64)
15
16 // Named Paths
17 //
18 access(all) let CollectionStoragePath: StoragePath
19 access(all) let CollectionPublicPath: PublicPath
20 access(all) let AdminStoragePath: StoragePath
21
22
23 access(all) var totalSupply: UInt64
24 access(all) var nextEditionID: UInt32
25 access(self) var editions: {UInt32: Edition}
26
27 access(all) struct EditionMetadata {
28 access(all) let editionID: UInt32
29 access(all) let name: String
30 access(all) let description: String
31 access(all) let imageURL: String
32 access(all) let circulatingCount: UInt64
33
34 init(editionID: UInt32, name: String, description: String, imageURL: String, circulatingCount: UInt64) {
35 self.editionID = editionID
36 self.name = name
37 self.description = description
38 self.imageURL = imageURL
39 self.circulatingCount = circulatingCount
40 }
41 }
42
43 access(all) struct Edition {
44 access(all) let editionID: UInt32
45 access(all) let name: String
46 access(all) let description: String
47 access(all) let imageURL: String
48 access(account) var nextSerialInEdition: UInt64
49
50 init(name: String, description: String, imageURL: String) {
51 self.editionID = Basketballs.nextEditionID
52 self.name = name
53 self.description = description
54 self.imageURL = imageURL
55 self.nextSerialInEdition = 1
56
57 Basketballs.nextEditionID = Basketballs.nextEditionID + (1 as UInt32)
58
59 emit EditionCreated(editionID: self.editionID, name: self.name, description: self.description, imageURL: self.imageURL)
60 }
61
62 access(all) fun mintBasketball(): @NFT {
63 let basketball: @NFT <- create NFT(editionID: self.editionID, serialNumber: self.nextSerialInEdition)
64
65 self.nextSerialInEdition = self.nextSerialInEdition + (1 as UInt64)
66
67 Basketballs.editions[self.editionID] = self
68
69 return <-basketball
70 }
71
72 access(all) fun mintBasketballs(quantity: UInt64): @Collection {
73 let newCollection <- create Collection()
74
75 var i: UInt64 = 0
76 while i < quantity {
77 newCollection.deposit(token: <- self.mintBasketball())
78 i = i + 1
79 }
80
81 return <- newCollection
82 }
83 }
84
85 // NFT
86 // A Basketball as an NFT
87 //
88 access(all) resource NFT: NonFungibleToken.NFT {
89 access(all) event ResourceDestroyed(id: UInt64 = self.id)
90
91 access(all) let id: UInt64
92 access(all) let editionID: UInt32
93 access(all) let serialNumber: UInt64
94
95 init(editionID: UInt32, serialNumber: UInt64) {
96 Basketballs.totalSupply = Basketballs.totalSupply + (1 as UInt64)
97 self.id = Basketballs.totalSupply
98 self.editionID = editionID
99 self.serialNumber = serialNumber
100
101 emit BasketballMinted(id: self.id, editionID: self.editionID, serialNumber: self.serialNumber)
102 }
103
104
105 access(all) fun createEmptyCollection(): @{NonFungibleToken.Collection} {
106 panic("TODO")
107 }
108
109 access(all) view fun getViews(): [Type] {
110 panic("TODO")
111 }
112
113 access(all) view fun resolveView(_ view: Type): AnyStruct? {
114 panic("TODO")
115 }
116}
117
118 access(all) resource interface BasketballsCollectionPublic {}
119
120 // Collection
121 // A collection of Basketball NFTs owned by an account
122 //
123 access(all) resource Collection: NonFungibleToken.Collection, BasketballsCollectionPublic, NonFungibleToken.Provider, NonFungibleToken.Receiver, NonFungibleToken.CollectionPublic {
124 // dictionary of NFT conforming tokens
125 // NFT is a resource type with an UInt64 ID field
126 //
127 access(all) var ownedNFTs: @{UInt64: {NonFungibleToken.NFT}}
128
129 // withdraw
130 // Removes an NFT from the collection and moves it to the caller
131 //
132 access(NonFungibleToken.Withdraw) fun withdraw(withdrawID: UInt64): @{NonFungibleToken.NFT} {
133 let token <- self.ownedNFTs.remove(key: withdrawID) ?? panic("missing NFT")
134
135 emit Withdraw(id: token.id, from: self.owner?.address)
136
137 return <-token
138 }
139
140 // deposit
141 // Takes a NFT and adds it to the collections dictionary
142 // and adds the ID to the id array
143 //
144 access(all) fun deposit(token: @{NonFungibleToken.NFT}) {
145 let token <- token as! @Basketballs.NFT
146
147 let id: UInt64 = token.id
148
149 // add the new token to the dictionary which removes the old one
150 let oldToken <- self.ownedNFTs[id] <- token
151
152 emit Deposit(id: id, to: self.owner?.address)
153
154 destroy oldToken
155 }
156
157 // getIDs
158 // Returns an array of the IDs that are in the collection
159 //
160 access(all) view fun getIDs(): [UInt64] {
161 return self.ownedNFTs.keys
162 }
163
164 // borrowNFT
165 // Gets a reference to an NFT in the collection
166 // so that the caller can read its metadata and call its methods
167 //
168 access(all) view fun borrowNFT(_ id: UInt64): &{NonFungibleToken.NFT}? {
169 return (&self.ownedNFTs[id] as &{NonFungibleToken.NFT}?)
170 }
171
172 // borrowBasketball
173 // Gets a reference to an NFT in the collection as a Basketball,
174 // exposing all of its fields (including the typeID).
175 // This is safe as there are no functions that can be called on the Basketball.
176 //
177 access(all) fun borrowBasketball(id: UInt64): &Basketballs.NFT? {
178 if self.ownedNFTs[id] != nil {
179 let ref = (&self.ownedNFTs[id] as &{NonFungibleToken.NFT}?)!
180 return ref as! &Basketballs.NFT
181 } else {
182 return nil
183 }
184 }
185
186 // initializer
187 //
188 init () {
189 self.ownedNFTs <- {}
190 }
191
192 access(all) view fun getSupportedNFTTypes(): {Type: Bool} {
193 panic("TODO")
194 }
195
196 access(all) view fun isSupportedNFTType(type: Type): Bool {
197 panic("TODO")
198 }
199
200 access(all) view fun getLength(): Int {
201 panic("TODO")
202 }
203 /// createEmptyCollection creates an empty Collection of the same type
204 /// and returns it to the caller
205 /// @return A an empty collection of the same type
206 access(all) fun createEmptyCollection(): @{NonFungibleToken.Collection} {
207 return <-Basketballs.createEmptyCollection(nftType: Type<@Basketballs.NFT>())
208 }
209}
210
211 access(all) resource Admin {
212
213 access(all) fun createEdition(name: String, description: String, imageURL: String): UInt32 {
214 let edition = Edition(name: name, description: description, imageURL: imageURL)
215
216 Basketballs.editions[edition.editionID] = edition
217
218 return edition.editionID
219 }
220
221 access(all) fun mintBasketball(editionID: UInt32): @NFT {
222 pre {
223 Basketballs.editions[editionID] != nil: "Mint failed: Edition does not exist"
224 }
225
226 let edition: Edition = Basketballs.editions[editionID]!;
227
228 let basketball: @NFT <- edition.mintBasketball()
229
230 return <-basketball
231 }
232
233 access(all) fun mintBasketballs(editionID: UInt32, quantity: UInt64): @Collection {
234 pre {
235 Basketballs.editions[editionID] != nil: "Mint failed: Edition does not exist"
236 }
237
238 let edition: Edition = Basketballs.editions[editionID]!;
239
240 let collection: @Collection <- edition.mintBasketballs(quantity: quantity)
241
242 return <-collection
243 }
244
245 access(all) fun createNewAdmin(): @Admin {
246 return <- create Admin()
247 }
248 }
249
250 access(all) fun createEmptyCollection(nftType: Type): @{NonFungibleToken.Collection} {
251 return <- create Collection()
252 }
253
254 // fetch
255 // Get a reference to a Basketball from an account's Collection, if available.
256 // If an account does not have a Basketballs.Collection, panic.
257 // If it has a collection but does not contain the itemId, return nil.
258 // If it has a collection and that collection contains the itemId, return a reference to that.
259 //
260 access(all) fun fetch(_ from: Address, itemID: UInt64): &Basketballs.NFT? {
261 let account = getAccount(from)
262 let collection = account.capabilities.borrow<&Basketballs.Collection>(/public/BasketballsCollection)
263 ?? panic("Couldn't get collection")
264
265 // We trust Basketballs.Collection.borowBasketball to get the correct itemID
266 // (it checks it before returning it).
267 return collection.borrowBasketball(id: itemID)
268 }
269
270 access(all) fun getAllEditions(): [Edition] {
271 return self.editions.values
272 }
273
274 access(all) fun getEditionMetadata(editionID: UInt32): EditionMetadata {
275 let edition = self.editions[editionID]!
276 let metadata = EditionMetadata(editionID: edition.editionID, name: edition.name, description: edition.description, imageURL: edition.imageURL, circulatingCount: edition.nextSerialInEdition - (1 as UInt64))
277 return metadata
278 }
279
280 // initializer
281 //
282 init() {
283 // Set our named paths
284 self.CollectionStoragePath = /storage/BasketballsCollection
285 self.CollectionPublicPath = /public/BasketballsCollection
286 self.AdminStoragePath = /storage/BasketballsAdmin
287
288 // Initialize the total supply
289 self.totalSupply = 0
290 self.editions = {}
291 self.nextEditionID = 1
292
293 self.account.storage.save(<- create Admin(), to: self.AdminStoragePath)
294
295 emit ContractInitialized()
296 }
297
298 access(all) view fun getContractViews(resourceType: Type?): [Type] {
299 panic("TODO")
300 }
301
302 access(all) view fun resolveContractView(resourceType: Type?, viewType: Type): AnyStruct? {
303 panic("TODO")
304 }
305}
306