Smart Contract
MotoGPCard
A.a49cc0ee46c54bfb.MotoGPCard
1import NonFungibleToken from 0x1d7e57aa55817448
2import MotoGPAdmin from 0xa49cc0ee46c54bfb
3import MotoGPCounter from 0xa49cc0ee46c54bfb
4import MetadataViews from 0x1d7e57aa55817448
5import MotoGPCardMetadata from 0xa49cc0ee46c54bfb
6
7pub contract MotoGPCard: NonFungibleToken {
8
9 pub fun getVersion(): String {
10 return "1.0.3"
11 }
12
13 // The total number of Cards in existence
14 pub var totalSupply: UInt64
15
16 // Event that emitted when the MotoGPCard contract is initialized
17 //
18 pub event ContractInitialized()
19
20 // Event that is emitted when a Card is withdrawn,
21 // indicating the owner of the collection that it was withdrawn from.
22 //
23 // If the collection is not in an account's storage, `from` will be `nil`.
24 //
25 pub event Withdraw(id: UInt64, from: Address?)
26
27 // Event that emitted when a Card is deposited to a collection.
28 //
29 // It indicates the owner of the collection that it was deposited to.
30 //
31 pub event Deposit(id: UInt64, to: Address?)
32
33
34 pub event Mint(id: UInt64)
35
36 pub event Burn(id: UInt64)
37
38 // An array UInt128s that represents cardID + serial keys
39 // This is primarily used to ensure there
40 // are no duplicates when we mint a new Card (NFT)
41 access(account) var allCards: [UInt128]
42
43 // NFT
44 // The NFT resource defines a specific Card
45 // that has an id, cardID, and serial.
46 // This resource will be created every time
47 // a pack opens and when we need to mint Cards.
48 //
49 // This NFT represents a Card. These names
50 // will be used interchangeably.
51 //
52 pub resource NFT: NonFungibleToken.INFT, MetadataViews.Resolver {
53 // The card's Issue ID (completely sequential)
54 pub let id: UInt64
55
56 // The card's cardID, which will be determined
57 // once the pack is opened
58 pub let cardID: UInt64
59
60 // The card's Serial, which will also be determined
61 // once the pack is opened
62 pub let serial: UInt64
63
64 // initializer
65 //
66 init(_cardID: UInt64, _serial: UInt64) {
67 let keyValue = UInt128(_cardID) + (UInt128(_serial) * (0x4000000000000000 as UInt128))
68 if (MotoGPCard.allCards.contains(keyValue)) {
69 panic("This cardID and serial combination already exists")
70 }
71 MotoGPCard.allCards.append(keyValue)
72
73 self.cardID = _cardID
74 self.serial = _serial
75
76 self.id = MotoGPCounter.increment("MotoGPCard")
77
78 MotoGPCard.totalSupply = MotoGPCard.totalSupply + (1 as UInt64)
79
80 emit Mint(id: self.id)
81 }
82
83 // NOTE: The method getCardMetadata(): MotoGPCardMetadata.Metadata? has been removed.
84 // Use methods getViews and resolveView instead to fetch metadata
85
86 destroy(){
87 MotoGPCard.totalSupply = MotoGPCard.totalSupply - (1 as UInt64)
88 emit Burn(id: self.id)
89 }
90
91 ///////////////////////////////
92 // Resolver interface methods
93 ///////////////////////////////
94
95 pub fun getViews(): [Type] {
96 return [
97 Type<MetadataViews.Display>(),
98 Type<MetadataViews.Royalties>(),
99 Type<MetadataViews.NFTCollectionData>(),
100 Type<MetadataViews.NFTCollectionDisplay>(),
101 Type<MetadataViews.ExternalURL>(),
102 Type<MetadataViews.Medias>(),
103 Type<MetadataViews.Traits>(),
104 Type<MotoGPCardMetadata.Riders>() // custom type
105 ]
106 }
107
108 pub fun resolveView(_ view: Type): AnyStruct? {
109 return MotoGPCardMetadata.resolveView(
110 view: view,
111 id: self.id,
112 cardID: self.cardID,
113 serial: self.serial,
114 // Below four arguments are passed to MotoGPCardMetadata (as opposed being hardcoded there) to avoid cyclic dependencies MotoGPCard <-> MotoGPCardMetadata
115 publicCollectionType: Type<&MotoGPCard.Collection{MotoGPCard.ICardCollectionPublic}>(),
116 publicLinkedType: Type<&MotoGPCard.Collection{MotoGPCard.ICardCollectionPublic, NonFungibleToken.CollectionPublic, NonFungibleToken.Receiver, MetadataViews.ResolverCollection}>(),
117 providerLinkedType: Type<&MotoGPCard.Collection{NonFungibleToken.Provider, NonFungibleToken.CollectionPublic, MetadataViews.ResolverCollection}>(),
118 createEmptyCollectionFunction: (fun (): @NonFungibleToken.Collection {
119 return <- MotoGPCard.createEmptyCollection()
120 })
121 )
122 }
123 }
124
125 // createNFT
126 // allows us to create an NFT from another contract in this
127 // account because we want to be able to mint NFTs
128 // in MotoGPPack
129 //
130 access(account) fun createNFT(cardID: UInt64, serial: UInt64): @NFT {
131 return <- create NFT(_cardID: cardID, _serial: serial)
132 }
133
134 // ICardCollectionPublic
135 // Defines an interface that specifies
136 // what fields and functions
137 // we want to expose to the public.
138 //
139 // Allows users to deposit Cards, read all the Card IDs,
140 // borrow a NFT reference to access a Card's ID,
141 // deposit a batch of Cards, and borrow a Card reference
142 // to access all of the Card's fields.
143 //
144 pub resource interface ICardCollectionPublic {
145 pub fun deposit(token: @NonFungibleToken.NFT)
146 pub fun getIDs(): [UInt64]
147 pub fun borrowNFT(id: UInt64): &NonFungibleToken.NFT
148
149 pub fun depositBatch(cardCollection: @NonFungibleToken.Collection)
150 pub fun borrowCard(id: UInt64): &MotoGPCard.NFT? {
151 // If the result isn't nil, the id of the returned reference
152 // should be the same as the argument to the function
153 post {
154 (result == nil) || (result?.id == id):
155 "Cannot borrow Card reference: The ID of the returned reference is incorrect"
156 }
157 }
158 }
159
160 // Collection
161 // This resource defines a collection of Cards
162 // that a user will have. We must give each user
163 // this collection so they can
164 // interact with Cards.
165 //
166 pub resource Collection: NonFungibleToken.Provider, NonFungibleToken.Receiver, NonFungibleToken.CollectionPublic, ICardCollectionPublic, MetadataViews.ResolverCollection {
167 // A dictionary that maps a Card's id to a
168 // Card in the collection. It holds all the
169 // Cards in a collection.
170 pub var ownedNFTs: @{UInt64: NonFungibleToken.NFT}
171
172 // deposit
173 // deposits a Card into the Collection
174 //
175 pub fun deposit(token: @NonFungibleToken.NFT) {
176 let token <- token as! @MotoGPCard.NFT
177
178 let id: UInt64 = token.id
179
180 // add the new Card to the dictionary which removes the old one
181 let oldToken <- self.ownedNFTs[id] <- token
182
183 // Only emit a deposit event if the Collection
184 // is in an account's storage
185 if self.owner?.address != nil {
186 emit Deposit(id: id, to: self.owner?.address)
187 }
188
189 destroy oldToken
190 }
191
192 // depositBatch
193 // This method deposits a collection of Cards into the
194 // user's Collection.
195 //
196 // This is primarily called by an Admin to
197 // deposit newly minted Cards into this Collection.
198 //
199 pub fun depositBatch(cardCollection: @NonFungibleToken.Collection) {
200 pre {
201 cardCollection.getIDs().length <= 100:
202 "Too many cards being deposited. Must be less than or equal to 100"
203 }
204
205 // Get an array of the IDs to be deposited
206 let keys = cardCollection.getIDs()
207
208 // Iterate through the keys in the collection and deposit each one
209 for key in keys {
210 self.deposit(token: <-cardCollection.withdraw(withdrawID: key))
211 }
212
213 // Destroy the empty Collection
214 destroy cardCollection
215 }
216
217 // withdraw
218 // withdraw removes a Card from the collection and moves it to the caller
219 //
220 pub fun withdraw(withdrawID: UInt64): @NonFungibleToken.NFT {
221 let token <- self.ownedNFTs.remove(key: withdrawID) ?? panic("missing NFT")
222
223 emit Withdraw(id: token.id, from: self.owner?.address)
224
225 return <-token
226 }
227
228 // getIDs
229 // returns the ids of all the Card this
230 // collection has
231 //
232 pub fun getIDs(): [UInt64] {
233 return self.ownedNFTs.keys
234 }
235
236 // borrowNFT
237 // borrowNFT gets a reference to an NFT in the collection
238 // so that the caller can read its id field
239 //
240 pub fun borrowNFT(id: UInt64): &NonFungibleToken.NFT {
241 return (&self.ownedNFTs[id] as &NonFungibleToken.NFT?)!
242 }
243
244 // borrowCard
245 // borrowCard returns a borrowed reference to a Card
246 // so that the caller can read data from it.
247 // They can use this to read its id, cardID, and serial
248 //
249 pub fun borrowCard(id: UInt64): &MotoGPCard.NFT? {
250 let ref = &self.ownedNFTs[id] as auth &NonFungibleToken.NFT?
251 return ref as! &MotoGPCard.NFT?
252 }
253
254 // ResolverCollection interface method
255 //
256 pub fun borrowViewResolver(id: UInt64): &AnyResource{MetadataViews.Resolver} {
257 let nft = (&self.ownedNFTs[id] as auth &NonFungibleToken.NFT?)!
258 let cardNFT = nft as! &MotoGPCard.NFT
259 return cardNFT as &AnyResource{MetadataViews.Resolver}
260 }
261
262 destroy() {
263 destroy self.ownedNFTs
264 }
265
266 init () {
267 self.ownedNFTs <- {}
268 }
269 }
270
271 // createEmptyCollection
272 // creates a new Collection resource and returns it.
273 // This will primarily be used to give a user a new Collection
274 // so they can store Cards
275 //
276 pub fun createEmptyCollection(): @Collection {
277 return <- create Collection()
278 }
279
280 init() {
281 self.totalSupply = 0
282 self.allCards = []
283
284 emit ContractInitialized()
285 }
286
287}