Smart Contract
MotoGPPack
A.a49cc0ee46c54bfb.MotoGPPack
1import NonFungibleToken from 0x1d7e57aa55817448
2import MetadataViews from 0x1d7e57aa55817448
3import MotoGPPackMetadata from 0xa49cc0ee46c54bfb
4
5pub contract MotoGPPack: NonFungibleToken {
6
7 pub fun getVersion(): String {
8 return "1.0.2"
9 }
10
11 // The total number of Packs that have been minted
12 pub var totalSupply: UInt64
13
14 // An dictionary of all the pack types that have been
15 // created using addPackType method defined
16 // in the MotoGPAdmin contract
17 //
18 // It maps the packType # to the
19 // information of that pack type
20 access(account) var packTypes: {UInt64: PackType}
21
22 pub event Mint(id: UInt64)
23
24 pub event Burn(id: UInt64)
25
26 // Event that emitted when the MotoGPPack contract is initialized
27 //
28 pub event ContractInitialized()
29
30 // Event that is emitted when a Pack is withdrawn,
31 // indicating the owner of the collection that it was withdrawn from.
32 //
33 // If the collection is not in an account's storage, `from` will be `nil`.
34 //
35 pub event Withdraw(id: UInt64, from: Address?)
36
37 // Event that emitted when a Pack is deposited to a collection.
38 //
39 // It indicates the owner of the collection that it was deposited to.
40 //
41 pub event Deposit(id: UInt64, to: Address?)
42
43 // PackInfo
44 // a struct that represents the info of a Pack.
45 // It is conveniant to have a struct because we
46 // can easily read from it without having to move
47 // resources around. Each PackInfo holds a
48 // packNumber and packType
49 //
50 pub struct PackInfo {
51 // The pack # of this pack type
52 pub var packNumber: UInt64
53
54 // An ID that represents that type of pack this is
55 pub var packType: UInt64
56
57 init(_packNumber: UInt64, _packType: UInt64) {
58 self.packNumber = _packNumber
59 self.packType = _packType
60 }
61 }
62
63 // NFT
64 // This resource defines a Pack with a PackInfo
65 // struct.
66 // After a Pack is opened, the Pack is destroyed and its id
67 // can never be created again.
68 //
69 // The NFT (Pack) resource is arbitrary in the sense that it doesn't
70 // actually hold Cards inside. However, by looking at a Pack's
71 // packType and mapping that to the # of Cards in a Pack,
72 // we will use that info when opening the Pack.
73 //
74 pub resource NFT: NonFungibleToken.INFT, MetadataViews.Resolver {
75 // The Pack's id (completely sequential)
76 pub let id: UInt64
77
78 pub var packInfo: PackInfo
79
80 init(_packNumber: UInt64, _packType: UInt64) {
81 let packTypeStruct: &PackType = (&MotoGPPack.packTypes[_packType] as &PackType?)!
82 // updates the number of packs minted for this packType
83 packTypeStruct.updateNumberOfPacksMinted()
84
85 // will panic if this packNumber already exists in this packType
86 packTypeStruct.addPackNumber(packNumber: _packNumber)
87
88 self.id = MotoGPPack.totalSupply
89 self.packInfo = PackInfo(_packNumber: _packNumber, _packType: _packType)
90
91 MotoGPPack.totalSupply = MotoGPPack.totalSupply + (1 as UInt64)
92
93 emit Mint(id: self.id)
94 }
95
96 destroy(){
97 emit Burn(id: self.id)
98 }
99
100 ///////////////////////////////
101 // Resolver interface methods
102 ///////////////////////////////
103
104 pub fun getViews(): [Type] {
105 return [
106 Type<MetadataViews.Display>(),
107 Type<MetadataViews.Royalties>(),
108 Type<MetadataViews.NFTCollectionData>(),
109 Type<MetadataViews.NFTCollectionDisplay>(),
110 Type<MetadataViews.ExternalURL>(),
111 Type<MetadataViews.Medias>(),
112 Type<MetadataViews.Traits>()
113 ]
114 }
115
116 pub fun resolveView(_ view: Type): AnyStruct? {
117 return MotoGPPackMetadata.resolveView(
118 view: view,
119 id: self.id,
120 packID: self.packInfo.packType,
121 serial: self.packInfo.packNumber,
122 // Below four arguments are passed to MotoGPPackMetadata (as opposed being hardcoded there) to avoid cyclic dependencies MotoGPPack <-> MotoGPPackMetadata
123 publicCollectionType: Type<&MotoGPPack.Collection{MotoGPPack.IPackCollectionPublic}>(),
124 publicLinkedType: Type<&MotoGPPack.Collection{MotoGPPack.IPackCollectionPublic, NonFungibleToken.CollectionPublic, NonFungibleToken.Receiver, MetadataViews.ResolverCollection}>(),
125 providerLinkedType: Type<&MotoGPPack.Collection{NonFungibleToken.Provider, NonFungibleToken.CollectionPublic, MetadataViews.ResolverCollection}>(),
126 createEmptyCollectionFunction: (fun (): @NonFungibleToken.Collection {
127 return <- MotoGPPack.createEmptyCollection()
128 })
129 )
130 }
131 }
132
133 // createPack
134 // allows us to create Packs from another contract
135 // in this account. This is helpful for
136 // allowing MotoGPAdmin to mint Packs.
137 //
138 access(account) fun createPack(packNumber: UInt64, packType: UInt64): @NFT {
139 return <- create NFT(_packNumber: packNumber, _packType: packType)
140 }
141
142 // PackType
143 // holds all the information for
144 // a specific pack type
145 //
146 pub struct PackType {
147
148 pub let packType: UInt64
149
150 // the number of packs of this pack type
151 // that have been minted
152 pub var numberOfPacksMinted: UInt64
153
154 // the number of cards that will be minted
155 // when a pack of this pack type is opened
156 pub let numberOfCards: UInt64
157
158 // the pack numbers that already exist of this
159 // pack type.
160 // This is primarily used so we don't create duplicate
161 // Packs with the same packNumber and packType
162 pub var assignedPackNumbers: {UInt64: Bool}
163
164 // updateNumberOfPacksMinted
165 // updates the number of Packs that have
166 // been minted for this specific pack type
167 //
168 access(contract) fun updateNumberOfPacksMinted() {
169 self.numberOfPacksMinted = self.numberOfPacksMinted + (1 as UInt64)
170 }
171
172 // addPackNumber
173 // updates the amount of packNumbers that
174 // belong to this PackType so we do not
175 // make duplicates when minting a Pack
176 //
177 access(contract) fun addPackNumber(packNumber: UInt64) {
178 if let assignedPackNumbers = self.assignedPackNumbers[packNumber] {
179 panic("The following pack number already exists: ".concat(packNumber.toString()))
180 } else {
181 self.assignedPackNumbers[packNumber] = true
182 }
183 }
184
185 init(_packType: UInt64, _numberOfCards: UInt64) {
186 self.packType = _packType
187 self.numberOfCards = _numberOfCards
188 self.numberOfPacksMinted = 0
189 self.assignedPackNumbers = {}
190 }
191 }
192
193 // IPackCollectionPublic
194 // This defines an interface to only expose a
195 // Collection of Packs to the public
196 //
197 // Allows users to deposit Packs, read all the Pack IDs,
198 // borrow a NFT reference to access a Pack's ID,
199 // and borrow a Pack reference
200 // to access all of the Pack's fields.
201 //
202 pub resource interface IPackCollectionPublic {
203 pub fun deposit(token: @NonFungibleToken.NFT)
204 pub fun getIDs(): [UInt64]
205 pub fun borrowNFT(id: UInt64): &NonFungibleToken.NFT
206
207 pub fun borrowPack(id: UInt64): &MotoGPPack.NFT? {
208 // If the result isn't nil, the id of the returned reference
209 // should be the same as the argument to the function
210 post {
211 (result == nil) || (result?.id == id):
212 "Cannot borrow Pack reference: The ID of the returned reference is incorrect"
213 }
214 }
215 }
216
217 // IPackCollectionAdminAccessible
218 // Exposes the openPack which allows an admin to
219 // open a pack in this collection.
220 //
221 pub resource interface IPackCollectionAdminAccessible {
222 //Keep for now for compatibility purposes.
223 }
224
225 // Collection
226 // a collection of Pack resources so that users can
227 // own Packs in a collection and trade them back and forth.
228 //
229 pub resource Collection: NonFungibleToken.Provider, NonFungibleToken.Receiver, NonFungibleToken.CollectionPublic, IPackCollectionPublic, IPackCollectionAdminAccessible, MetadataViews.ResolverCollection {
230 // A dictionary that maps ids to the pack with that id
231 pub var ownedNFTs: @{UInt64: NonFungibleToken.NFT}
232
233 // deposit
234 // deposits a Pack into the users Collection
235 //
236 pub fun deposit(token: @NonFungibleToken.NFT) {
237 let token <- token as! @MotoGPPack.NFT
238
239 let id: UInt64 = token.id
240
241 // add the new Pack to the dictionary which removes the old one
242 let oldToken <- self.ownedNFTs[id] <- token
243
244 // Only emit a deposit event if the Collection
245 // is in an account's storage
246 if self.owner?.address != nil {
247 emit Deposit(id: id, to: self.owner?.address)
248 }
249
250 destroy oldToken
251 }
252
253 // withdraw
254 // withdraws a Pack from the collection
255 //
256 pub fun withdraw(withdrawID: UInt64): @NonFungibleToken.NFT {
257 let token <- self.ownedNFTs.remove(key: withdrawID) ?? panic("missing NFT")
258
259 emit Withdraw(id: token.id, from: self.owner?.address)
260
261 return <-token
262 }
263
264 // getIDs
265 // returns the ids of all the Packs this
266 // collection has
267 //
268 pub fun getIDs(): [UInt64] {
269 return self.ownedNFTs.keys
270 }
271
272 // borrowNFT
273 // borrowNFT gets a reference to an NFT in the collection
274 // so that the caller can read its id
275 //
276 pub fun borrowNFT(id: UInt64): &NonFungibleToken.NFT {
277 return (&self.ownedNFTs[id] as &NonFungibleToken.NFT?)!
278 }
279
280 // borrowPack
281 // borrowPack returns a borrowed reference to a Pack
282 // so that the caller can read data from it.
283 // They can use this to read its PackInfo and id
284 //
285 pub fun borrowPack(id: UInt64): &MotoGPPack.NFT? {
286 let ref = &self.ownedNFTs[id] as auth &NonFungibleToken.NFT?
287 return ref as! &MotoGPPack.NFT?
288 }
289
290 // ResolverCollection interface method
291 //
292 pub fun borrowViewResolver(id: UInt64): &AnyResource{MetadataViews.Resolver} {
293 let nft = (&self.ownedNFTs[id] as auth &NonFungibleToken.NFT?)!
294 let packNFT = nft as! &MotoGPPack.NFT
295 return packNFT as &AnyResource{MetadataViews.Resolver}
296 }
297
298 destroy() {
299 destroy self.ownedNFTs
300 }
301
302 init() {
303 self.ownedNFTs <- {}
304 }
305 }
306
307 // createEmptyCollection
308 // creates an empty Collection so that users
309 // can be able to receive and deal with Pack resources.
310 //
311 pub fun createEmptyCollection(): @Collection {
312 return <- create Collection()
313 }
314
315 // getPackTypeInfo
316 // returns a PackType struct, which represents the info
317 // of a specific PackType that is passed in
318 //
319 pub fun getPackTypeInfo(packType: UInt64): PackType {
320 return self.packTypes[packType] ?? panic("This pack type does not exist")
321 }
322
323 // addPackType
324 // allows us to add new pack types from another contract
325 // in this account. This is helpful for
326 // allowing MotoGPAdmin to add new pack types.
327 //
328 access(account) fun addPackType(packType: UInt64, numberOfCards: UInt64) {
329 pre {
330 self.packTypes[packType] == nil:
331 "This pack type already exists!"
332 }
333 // Adds this pack type
334 self.packTypes[packType] = self.PackType(_packType: packType, _numberOfCards: numberOfCards)
335 }
336
337 init() {
338 self.totalSupply = 0
339 self.packTypes = {}
340
341 emit ContractInitialized()
342 }
343}