Smart Contract
HWGarageCardV2
A.d0bcefdf1e67ea85.HWGarageCardV2
1/*
2*
3* An NFT contract for redeeming/minting tokens by series
4*
5*
6*/
7
8import NonFungibleToken from 0x1d7e57aa55817448
9import FungibleToken from 0xf233dcee88fe0abe
10import MetadataViews from 0x1d7e57aa55817448
11import ViewResolver from 0x1d7e57aa55817448
12
13
14access(all) contract HWGarageCardV2: NonFungibleToken {
15
16 /*
17 * NonFungibleToken Standard Events
18 */
19 access(all) event ContractInitialized()
20 access(all) event Withdraw(id: UInt64, from: Address?)
21 access(all) event Deposit(id: UInt64, to: Address?)
22
23 /*
24 * Project Events
25 */
26 access(all) event Mint(id: UInt64)
27 access(all) event Burn(id: UInt64)
28 access(all) event DepositEvent(
29 uuid: UInt64
30 , id: UInt64
31 , seriesId: UInt64
32 , editionId: UInt64
33 , to: Address?
34 )
35
36 access(all) event TransferEvent(
37 uuid: UInt64
38 , id: UInt64
39 , seriesId: UInt64
40 , editionId: UInt64
41 , to: Address?
42 )
43
44 /*
45 * Named Paths
46 */
47 access(all) let CollectionStoragePath: StoragePath
48 access(all) let CollectionPublicPath: PublicPath
49
50 /*
51 * NonFungibleToken Standard Fields
52 */
53 access(all) var totalSupply: UInt64
54
55 /*
56 * Card State Variables
57 */
58 access(self) var name: String
59 access(account) var currentCardEditionIdByPackSeriesId: {UInt64: UInt64}
60
61 access(all) resource NFT: NonFungibleToken.NFT {
62 access(all) let id: UInt64
63 // the pack series this card came from
64 access(all) let packSeriesID: UInt64
65 access(all) let cardEditionID: UInt64
66 access(all) let packHash: String
67 access(all) let redeemable: String
68 access(all) let metadata: {String: String}
69
70
71 init(
72 id: UInt64
73 , packSeriesID: UInt64
74 , cardEditionID: UInt64
75 , packHash: String
76 , redeemable: String
77 , metadata: {String: String}
78 ) {
79 self.id = id
80 self.packSeriesID = packSeriesID
81 self.cardEditionID = cardEditionID
82 self.packHash = packHash
83 self.redeemable = redeemable
84 self.metadata = metadata
85 emit Mint(id: self.id)
86 }
87
88
89 access(all) fun createEmptyCollection(): @{NonFungibleToken.Collection} {
90 return <-HWGarageCardV2.createEmptyCollection(nftType: Type<@HWGarageCardV2.NFT>())
91 }
92
93 access(all) view fun getViews(): [Type] {
94 return [
95 Type<MetadataViews.Display>(),
96 Type<MetadataViews.ExternalURL>(),
97 Type<MetadataViews.NFTCollectionData>(),
98 Type<MetadataViews.NFTCollectionDisplay>(),
99 Type<MetadataViews.Royalties>(),
100 Type<MetadataViews.Traits>(),
101 Type<MetadataViews.Rarity>()
102 ]
103 }
104
105 access(all) fun resolveView(_ view: Type): AnyStruct? {
106 switch view {
107 case Type<MetadataViews.Display>():
108 var ipfsImage = MetadataViews.IPFSFile(
109 cid: self.metadata["thumbnailCID"] ?? "ThumbnailCID not set"
110 , path: self.metadata["thumbnailPath"] ?? ""
111 )
112 return MetadataViews.Display(
113 name: self.metadata["cardName"] ?? "Hot Wheels Garage Card Series ".concat(self.packSeriesID.toString()).concat(" #").concat(self.cardEditionID.toString()),
114 description: self.metadata["cardDescription"] ?? "Digital Card Collectable from Hot Wheels Garage" ,
115 thumbnail: ipfsImage
116 )
117
118 case Type<MetadataViews.ExternalURL>():
119 return MetadataViews.ExternalURL(
120 self.metadata["url"] ?? ""
121 )
122
123 case Type<MetadataViews.NFTCollectionData>():
124 return HWGarageCardV2.resolveContractView(resourceType: Type<@HWGarageCardV2.NFT>(), viewType: Type<MetadataViews.NFTCollectionData>())
125
126 case Type<MetadataViews.NFTCollectionDisplay>():
127 return HWGarageCardV2.resolveContractView(resourceType: Type<@HWGarageCardV2.NFT>(), viewType: Type<MetadataViews.NFTCollectionDisplay>())
128 case Type<MetadataViews.Traits>():
129 let exludedTraits = [
130 "thumbnailPath"
131 , "thumbnailCID"
132 , "collectionName"
133 , "collectionDescription"
134 , "cardDescription"
135 , "url"
136 ]
137 let traitsView = MetadataViews.dictToTraits(
138 dict: self.metadata,
139 excludedNames: exludedTraits
140 )
141
142 return traitsView
143 case Type<MetadataViews.Royalties>():
144 return HWGarageCardV2.resolveContractView(resourceType: Type<@HWGarageCardV2.NFT>(), viewType: Type<MetadataViews.Royalties>())
145 case Type<MetadataViews.Rarity>():
146 let rarityDescription = self.metadata["rarity"]
147 return MetadataViews.Rarity(
148 score: nil
149 , max: nil
150 ,description: rarityDescription
151 )
152 }
153 return nil
154 }
155
156
157 }
158
159 access(all) resource interface CardCollectionPublic {}
160
161 access(all) resource Collection: CardCollectionPublic, NonFungibleToken.Collection {
162 access(all) var ownedNFTs: @{UInt64: {NonFungibleToken.NFT}}
163
164 init() {
165 self.ownedNFTs <- {}
166 }
167
168 /// getSupportedNFTTypes returns a list of NFT types that this receiver accepts
169 access(all) view fun getSupportedNFTTypes(): {Type: Bool}{
170 let supportedTypes: {Type: Bool} = {}
171 supportedTypes[Type<@HWGarageCardV2.NFT>()] = true
172 return supportedTypes
173 }
174
175 /// Returns whether or not the given type is accepted by the collection
176 /// A collection that can accept any type should just return true by default
177 access(all) view fun isSupportedNFTType(type: Type): Bool {
178 return type == Type<@HWGarageCardV2.NFT>()
179 }
180
181 access(NonFungibleToken.Withdraw) fun withdraw(withdrawID: UInt64): @{NonFungibleToken.NFT} {
182 let token <- self.ownedNFTs.remove(key: withdrawID) ?? panic("missing NFT")
183
184 emit Withdraw(
185 id: token.id,
186 from: self.owner?.address
187 )
188
189 return <-token
190 }
191
192 access(all) fun deposit(token: @{NonFungibleToken.NFT}) {
193 let HWGarageCardV2 <- token as! @HWGarageCardV2.NFT
194 let HWGarageCardV2UUID: UInt64 = HWGarageCardV2.uuid
195 let HWGarageCardV2SeriesId: UInt64 = HWGarageCardV2.packSeriesID
196 let HWGarageCardV2ID: UInt64 = HWGarageCardV2.id
197 let HWGarageCardV2cardEditionID: UInt64 = HWGarageCardV2.cardEditionID
198
199 self.ownedNFTs[HWGarageCardV2ID] <-! HWGarageCardV2
200
201 emit Deposit(
202 id: HWGarageCardV2ID,
203 to: self.owner?.address
204 )
205
206 emit DepositEvent(
207 uuid: HWGarageCardV2UUID,
208 id: HWGarageCardV2ID,
209 seriesId: HWGarageCardV2SeriesId,
210 editionId: HWGarageCardV2cardEditionID,
211 to: self.owner?.address
212 )
213 }
214
215 access(all) view fun getIDs(): [UInt64] {
216 return self.ownedNFTs.keys
217 }
218
219 access(all) view fun borrowNFT(_ id: UInt64): &{NonFungibleToken.NFT}? {
220 return (&self.ownedNFTs[id])
221 }
222
223 access(all) view fun borrowCard(id: UInt64): &NFT? {
224 if let cardRef: &{NonFungibleToken.NFT} = &self.ownedNFTs[id] {
225 return cardRef as! &NFT
226 } else {
227 return nil
228 }
229 }
230
231 access(all) view fun borrowViewResolver(id: UInt64): &{ViewResolver.Resolver}? {
232 if let nftRef: &{NonFungibleToken.NFT} = &self.ownedNFTs[id] {
233 return nftRef as &{ViewResolver.Resolver}
234 }
235 return nil
236 }
237
238 /// Allows a given function to iterate through the list
239 /// of owned NFT IDs in a collection without first
240 /// having to load the entire list into memory
241 access(all) fun forEachID(_ f: fun(UInt64): Bool) {
242 self.ownedNFTs.forEachKey(f)
243 }
244
245 access(all) fun createEmptyCollection(): @{NonFungibleToken.Collection} {
246 return <- HWGarageCardV2.createEmptyCollection(nftType: Type<@HWGarageCardV2.NFT>())
247 }
248 }
249
250
251 /*
252 * Public Functions
253 */
254
255 access(all) fun createEmptyCollection(nftType: Type): @{NonFungibleToken.Collection} {
256 return <- create Collection()
257 }
258
259 access(all) view fun getTotalSupply(): UInt64 {
260 return self.totalSupply
261 }
262
263 access(all) view fun getName(): String {
264 return self.name
265 }
266
267 access(all) fun transfer(uuid: UInt64, id: UInt64, packSeriesId: UInt64, cardEditionId: UInt64, toAddress: Address){
268
269 let HWGarageCardV2UUID: UInt64 = uuid
270 let HWGarageCardV2SeriesId: UInt64 = packSeriesId
271 let HWGarageCardV2ID: UInt64 = id
272 let HWGarageCardV2cardEditionID: UInt64 = cardEditionId
273
274 emit TransferEvent(
275 uuid: HWGarageCardV2UUID
276 , id: HWGarageCardV2ID
277 , seriesId: HWGarageCardV2SeriesId
278 , editionId: HWGarageCardV2cardEditionID
279 , to: toAddress)
280 }
281 access(all) view fun getContractViews(resourceType: Type?): [Type] {
282 return [
283 Type<MetadataViews.NFTCollectionData>(),
284 Type<MetadataViews.NFTCollectionDisplay>(),
285 Type<MetadataViews.Royalties>()
286 ]
287 }
288
289 access(all) fun resolveContractView(resourceType: Type?, viewType: Type): AnyStruct? {
290 switch viewType {
291 case Type<MetadataViews.NFTCollectionData>():
292 return MetadataViews.NFTCollectionData(
293 storagePath: HWGarageCardV2.CollectionStoragePath,
294 publicPath: HWGarageCardV2.CollectionPublicPath,
295 publicCollection: Type<&HWGarageCardV2.Collection>(),
296 publicLinkedType: Type<&HWGarageCardV2.Collection>(),
297 createEmptyCollectionFunction: (fun(): @{NonFungibleToken.Collection} {
298 return <- HWGarageCardV2.createEmptyCollection(nftType: Type<@HWGarageCardV2.NFT>())})
299 )
300
301 case Type<MetadataViews.NFTCollectionDisplay>():
302 let externalURL = MetadataViews.ExternalURL(
303 ""
304 )
305
306 let squareImage = MetadataViews.Media(
307 file: MetadataViews.HTTPFile(
308 url: ""
309 ),
310 mediaType: "image/png")
311
312 let bannerImage = MetadataViews.Media(
313 file: MetadataViews.HTTPFile(
314 url: ""
315 ),
316 mediaType: "image/png")
317
318 let socialMap: {String: MetadataViews.ExternalURL} = {
319 "facebook": MetadataViews.ExternalURL(
320 "https://www.facebook.com/hotwheels"
321 ),
322 "instagram": MetadataViews.ExternalURL(
323 "https://www.instagram.com/hotwheelsofficial/"
324 ),
325 "twitter": MetadataViews.ExternalURL(
326 "https://twitter.com/Hot_Wheels"
327 ),
328 "discord": MetadataViews.ExternalURL(
329 "https://discord.gg/mattel"
330 )
331 }
332 return MetadataViews.NFTCollectionDisplay(
333 name: "Hot Wheels Garage Card",
334 description: "Digital Collectable from Hot Wheels Garage",
335 externalURL: externalURL,
336 squareImage: squareImage,
337 bannerImage: bannerImage,
338 socials: socialMap
339 )
340 case Type<MetadataViews.Royalties>():
341 let flowReciever = getAccount(0xf86e2f015cd692be).capabilities.get<&{FungibleToken.Receiver}>(/public/flowTokenReceiver)
342 return MetadataViews.Royalties([
343 MetadataViews.Royalty(
344 receiver:flowReciever
345 , cut: 0.05
346 , description: "Mattel 5% Royalty")
347 ]
348 )
349 }
350 return nil
351 }
352
353 /*
354 * Admin Functions
355 */
356 access(account) fun addNewSeries(newCardSeriesID: UInt64){
357 self.currentCardEditionIdByPackSeriesId.insert(key: newCardSeriesID, 0)
358 }
359
360
361 access(account) fun updateCurrentEditionIdByPackSeriesId(packSeriesID: UInt64, cardSeriesEdition: UInt64){
362 self.currentCardEditionIdByPackSeriesId[packSeriesID] = cardSeriesEdition
363 }
364
365
366 access(account) fun mint(
367 nftID: UInt64
368 , packSeriesID: UInt64
369 , cardEditionID: UInt64
370 , packHash: String
371 , redeemable: String
372 , metadata: {String: String}
373 ): @{NonFungibleToken.NFT} {
374
375 self.totalSupply = self.getTotalSupply() + 1
376
377 self.currentCardEditionIdByPackSeriesId[packSeriesID] = self.currentCardEditionIdByPackSeriesId[packSeriesID]! + 1
378
379 return <- create NFT(
380 id: nftID
381 , packSeriesID: packSeriesID
382 , cardEditionID: self.currentCardEditionIdByPackSeriesId[packSeriesID]!
383 , packHash: packHash
384 , redeemable: redeemable
385 , metadata: metadata
386 )
387 }
388
389 // initialize contract state variables
390 init(){
391 self.name = "Hot Wheels Garage Card v2"
392 self.totalSupply = 0
393 self.currentCardEditionIdByPackSeriesId = {1 : 0}
394
395 // set the named paths
396 self.CollectionStoragePath = /storage/HWGarageCardV2Collection
397 self.CollectionPublicPath = /public/HWGarageCardV2Collection
398
399 // create a collection resource and save it to storage
400 let collection: @HWGarageCardV2.Collection <- create Collection()
401 self.account.storage.save(<-collection, to: self.CollectionStoragePath)
402
403 let collectionCap = self.account.capabilities.storage.issue<&HWGarageCardV2.Collection>(self.CollectionStoragePath)
404 self.account.capabilities.publish(collectionCap, at: self.CollectionPublicPath)
405
406 emit ContractInitialized()
407 }
408
409
410}
411