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