Smart Contract
SGKCLDRAAAB
A.70d460a972f408e0.SGKCLDRAAAB
1// SPDX-License-Identifier: UNLICENSED
2//
3// Description: Attack On Titan Legacy
4// This is NonFungibleToken and Anique NFT.
5//
6// authors: Atsushi Otani atsushi.ootani@anique.jp
7//
8import NonFungibleToken from 0x1d7e57aa55817448
9import Anique from 0xe2e1689b53e92a82
10
11pub contract SGKCLDRAAAB: NonFungibleToken, Anique {
12 // -----------------------------------------------------------------------
13 // SGKCLDRAAAB contract Events
14 // -----------------------------------------------------------------------
15
16 // Events for Contract-Related actions
17 //
18 // Emitted when the SGKCLDRAAAB contract is created
19 pub event ContractInitialized()
20
21 // Events for Item-Related actions
22 //
23 // Emitted when a new Item struct is created
24 pub event ItemCreated(id: UInt32, metadata: {String:String})
25
26 // Events for Collectible-Related actions
27 //
28 // Emitted when an CollectibleData NFT is minted
29 pub event CollectibleMinted(collectibleID: UInt64, itemID: UInt32, serialNumber: UInt32)
30 // Emitted when an CollectibleData NFT is destroyed
31 pub event CollectibleDestroyed(collectibleID: UInt64)
32
33 // events for Collection-related actions
34 //
35 // Emitted when an CollectibleData is withdrawn from a Collection
36 pub event Withdraw(id: UInt64, from: Address?)
37 // Emitted when an CollectibleData is deposited into a Collection
38 pub event Deposit(id: UInt64, to: Address?)
39
40 // paths
41 pub let collectionStoragePath: StoragePath
42 pub let collectionPublicPath: PublicPath
43 pub let collectionPrivatePath: PrivatePath
44 pub let adminStoragePath: StoragePath
45 pub let saleCollectionStoragePath: StoragePath
46 pub let saleCollectionPublicPath: PublicPath
47
48 // -----------------------------------------------------------------------
49 // SGKCLDRAAAB contract-level fields.
50 // These contain actual values that are stored in the smart contract.
51 // -----------------------------------------------------------------------
52
53 // fields for Item-related
54 //
55 // variable size dictionary of Item resources
56 access(self) var items: @{UInt32: Item}
57
58 // The ID that is used to create Items.
59 pub var nextItemID: UInt32
60
61 // fields for Collectible-related
62 //
63 // Total number of CollectibleData NFTs that have been minted ever.
64 pub var totalSupply: UInt64
65
66 // -----------------------------------------------------------------------
67 // SGKCLDRAAAB contract-level Composite Type definitions
68 // -----------------------------------------------------------------------
69
70 // The structure that represents Item
71 // each digital content which SGKCLDRAAAB deal with on Flow
72 //
73 pub struct ItemData {
74
75 pub let itemID: UInt32
76
77 pub let metadata: {String: String}
78
79 init(itemID: UInt32) {
80 let item = (&SGKCLDRAAAB.items[itemID] as &Item?)!
81
82 self.itemID = item.itemID
83 self.metadata = item.metadata
84 }
85 }
86
87 // Item is a resource type that contains the functions to mint Collectibles.
88 //
89 // It is stored in a private field in the contract so that
90 // the admin resource can call its methods and that there can be
91 // public getters for some of its fields
92 //
93 // The admin can mint Collectibles that refer from Item.
94 pub resource Item {
95
96 // unique ID for the Item
97 pub let itemID: UInt32
98
99 // Stores all the metadata about the item as a string mapping
100 // This is not the long term way NFT metadata will be stored. It's a temporary
101 // construct while we figure out a better way to do metadata.
102 //
103 pub let metadata: {String: String}
104
105 // The number of Collectibles that have been minted per Item.
106 access(contract) var numberMintedPerItem: UInt32
107
108 init(metadata: {String: String}) {
109 pre {
110 metadata.length != 0: "New Item metadata cannot be empty"
111 }
112 self.itemID = SGKCLDRAAAB.nextItemID
113 self.metadata = metadata
114 self.numberMintedPerItem = 0
115
116 // increment the nextItemID so that it isn't used again
117 SGKCLDRAAAB.nextItemID = SGKCLDRAAAB.nextItemID + 1
118
119 emit ItemCreated(id: self.itemID, metadata: metadata)
120 }
121
122 // mintCollectible mints a new Collectible and returns the newly minted Collectible
123 //
124 // Returns: The NFT that was minted
125 //
126 pub fun mintCollectible(): @NFT {
127 // get the number of Collectibles that have been minted for this Item
128 // to use as this Collectible's serial number
129 let numInItem = self.numberMintedPerItem
130
131 // mint the new Collectible
132 let newCollectible: @NFT <- create NFT(serialNumber: numInItem + 1,
133 itemID: self.itemID)
134
135 // Increment the count of Collectibles minted for this Item
136 self.numberMintedPerItem = numInItem + 1
137
138 return <-newCollectible
139 }
140
141 // batchMintCollectible mints an arbitrary quantity of Collectibles
142 // and returns them as a Collection
143 //
144 // Parameters: itemID: the ID of the Item that the Collectibles are minted for
145 // quantity: The quantity of Collectibles to be minted
146 //
147 // Returns: Collection object that contains all the Collectibles that were minted
148 //
149 pub fun batchMintCollectible(quantity: UInt64): @Collection {
150 let newCollection <- create Collection()
151
152 var i: UInt64 = 0
153 while i < quantity {
154 newCollection.deposit(token: <-self.mintCollectible())
155 i = i + 1
156 }
157
158 return <-newCollection
159 }
160
161 // Returns: the number of Collectibles
162 pub fun getNumberMinted(): UInt32 {
163 return self.numberMintedPerItem
164 }
165 }
166
167 // The structure holds metadata of an Collectible
168 pub struct CollectibleData {
169 // The ID of the Item that the Collectible references
170 pub let itemID: UInt32
171
172 // The place in the Item that this Collectible was minted
173 pub let serialNumber: UInt32
174
175 init(itemID: UInt32, serialNumber: UInt32) {
176 self.itemID = itemID
177 self.serialNumber = serialNumber
178 }
179 }
180
181 // The resource that represents the CollectibleData NFTs
182 //
183 pub resource NFT: NonFungibleToken.INFT, Anique.INFT {
184
185 // Global unique collectibleData ID
186 pub let id: UInt64
187
188 // Struct of Collectible metadata
189 pub let data: CollectibleData
190
191 init(serialNumber: UInt32, itemID: UInt32) {
192 // Increment the global Collectible IDs
193 SGKCLDRAAAB.totalSupply = SGKCLDRAAAB.totalSupply + 1
194
195 // set id
196 self.id = SGKCLDRAAAB.totalSupply
197
198 // Set the metadata struct
199 self.data = CollectibleData(itemID: itemID, serialNumber: serialNumber)
200
201 emit CollectibleMinted(collectibleID: self.id, itemID: itemID, serialNumber: self.data.serialNumber)
202 }
203
204 destroy() {
205 emit CollectibleDestroyed(collectibleID: self.id)
206 }
207 }
208
209 // interface that represents SGKCLDRAAAB collections to public
210 // extends of NonFungibleToken.CollectionPublic
211 pub resource interface CollectionPublic {
212
213 pub fun deposit(token: @NonFungibleToken.NFT)
214 pub fun getIDs(): [UInt64]
215 pub fun borrowNFT(id: UInt64): &NonFungibleToken.NFT
216
217 // deposit multi tokens
218 pub fun batchDeposit(tokens: @Anique.Collection)
219
220 // contains NFT
221 pub fun contains(id: UInt64): Bool
222
223 // borrow NFT as SGKCLDRAAAB token
224 pub fun borrowSGKCLDRAAABCollectible(id: UInt64): auth &NFT
225 }
226
227 // Collection is a resource that every user who owns NFTs
228 // will store in their account to manage their NFTs
229 //
230 pub resource Collection: CollectionPublic, NonFungibleToken.Receiver, NonFungibleToken.Provider, NonFungibleToken.CollectionPublic {
231 // Dictionary of CollectibleData conforming tokens
232 // NFT is a resource type with a UInt64 ID field
233 pub var ownedNFTs: @{UInt64: NonFungibleToken.NFT}
234
235 init() {
236 self.ownedNFTs <- {}
237 }
238
239 // withdraw removes a Collectible from the Collection and moves it to the caller
240 //
241 // Parameters: withdrawID: The ID of the NFT
242 // that is to be removed from the Collection
243 //
244 // returns: @NonFungibleToken.NFT the token that was withdrawn
245 pub fun withdraw(withdrawID: UInt64): @NonFungibleToken.NFT {
246
247 // Remove the nft from the Collection
248 let token <- self.ownedNFTs.remove(key: withdrawID)
249 ?? panic("Cannot withdraw: Collectible does not exist in the collection")
250
251 emit Withdraw(id: token.id, from: self.owner?.address)
252
253 // Return the withdrawn token
254 return <- token
255 }
256
257 // batchWithdraw withdraws multiple tokens and returns them as a Collection
258 //
259 // Parameters: collectibleIds: An array of IDs to withdraw
260 //
261 // Returns: @NonFungibleToken.Collection: A collection that contains
262 // the withdrawn collectibles
263 //
264 pub fun batchWithdraw(collectibleIds: [UInt64]): @Anique.Collection {
265 // Create a new empty Collection
266 var batchCollection <- create Collection()
267
268 // Iterate through the collectibleIds and withdraw them from the Collection
269 for collectibleID in collectibleIds {
270 batchCollection.deposit(token: <-self.withdraw(withdrawID: collectibleID))
271 }
272
273 // Return the withdrawn tokens
274 return <-batchCollection
275 }
276
277 // deposit takes a Collectible and adds it to the Collections dictionary
278 //
279 // Parameters: token: the NFT to be deposited in the collection
280 //
281 pub fun deposit(token: @NonFungibleToken.NFT) {
282
283 // Cast the deposited token as an SGKCLDRAAAB NFT to make sure
284 // it is the correct type
285 let token <- token as! @SGKCLDRAAAB.NFT
286
287 // Get the token's ID
288 let id = token.id
289
290 // Add the new token to the dictionary
291 let oldToken <- self.ownedNFTs[id] <- token
292
293 // Only emit a deposit event if the Collection
294 // is in an account's storage
295 if self.owner?.address != nil {
296 emit Deposit(id: id, to: self.owner?.address)
297 }
298
299 // Destroy the empty old token that was "removed"
300 destroy oldToken
301 }
302
303 // batchDeposit takes a Collection object as an argument
304 // and deposits each contained NFT into this Collection
305 pub fun batchDeposit(tokens: @Anique.Collection) {
306
307 // Get an array of the IDs to be deposited
308 let keys = tokens.getIDs()
309
310 // Iterate through the keys in the collection and deposit each one
311 for key in keys {
312 self.deposit(token: <-tokens.withdraw(withdrawID: key))
313 }
314
315 // Destroy the empty Collection
316 destroy tokens
317 }
318
319 // getIDs returns an array of the IDs that are in the Collection
320 pub fun getIDs(): [UInt64] {
321 return self.ownedNFTs.keys
322 }
323
324 // contains returns whether ID is in the Collection
325 pub fun contains(id: UInt64): Bool {
326 return self.ownedNFTs[id] != nil
327 }
328
329 // borrowNFT Returns a borrowed reference to a Collectible in the Collection
330 // so that the caller can read its ID
331 //
332 // Parameters: id: The ID of the NFT to get the reference for
333 //
334 // Returns: A reference to the NFT
335 //
336 // Note: This only allows the caller to read the ID of the NFT,
337 // not any SGKCLDRAAAB specific data. Please use borrowCollectible to
338 // read Collectible data.
339 //
340 pub fun borrowNFT(id: UInt64): &NonFungibleToken.NFT {
341 return (&self.ownedNFTs[id] as &NonFungibleToken.NFT?)!
342 }
343
344 pub fun borrowAniqueNFT(id: UInt64): auth &Anique.NFT {
345 let nft = (&self.ownedNFTs[id] as auth &NonFungibleToken.NFT?)!
346 return nft as! auth &Anique.NFT
347 }
348
349 // borrowSGKCLDRAAABCollectible returns a borrowed reference
350 // to an SGKCLDRAAAB Collectible
351 pub fun borrowSGKCLDRAAABCollectible(id: UInt64): auth &NFT {
352 pre {
353 self.ownedNFTs[id] != nil: "NFT does not exist in the collection!"
354 }
355 let nft = (&self.ownedNFTs[id] as auth &NonFungibleToken.NFT?)!
356 return nft as! auth &NFT
357 }
358
359 // If a transaction destroys the Collection object,
360 // All the NFTs contained within are also destroyed!
361 //
362 destroy() {
363 destroy self.ownedNFTs
364 }
365 }
366
367 // Admin is a special authorization resource that
368 // allows the owner to perform important functions to modify the
369 // various aspects of the Items, CollectibleDatas, etc.
370 //
371 pub resource Admin {
372
373 // createItem creates a new Item struct
374 // and stores it in the Items dictionary field in the SGKCLDRAAAB smart contract
375 //
376 // Parameters: metadata: A dictionary mapping metadata titles to their data
377 // example: {"Title": "Excellent Anime", "Author": "John Smith"}
378 //
379 // Returns: the ID of the new Item object
380 //
381 pub fun createItem(metadata: {String: String}): UInt32 {
382 // Create the new Item
383 var newItem <- create Item(metadata: metadata)
384 let itemId = newItem.itemID
385
386 // Store it in the contract storage
387 SGKCLDRAAAB.items[newItem.itemID] <-! newItem
388
389 return itemId
390 }
391
392 // borrowItem returns a reference to a Item in the SGKCLDRAAAB
393 // contract so that the admin can call methods on it
394 //
395 // Parameters: itemID: The ID of the Item that you want to
396 // get a reference to
397 //
398 // Returns: A reference to the Item with all of the fields
399 // and methods exposed
400 //
401 pub fun borrowItem(itemID: UInt32): &Item {
402 pre {
403 SGKCLDRAAAB.items[itemID] != nil: "Cannot borrow Item: The Item doesn't exist"
404 }
405
406 return (&SGKCLDRAAAB.items[itemID] as &Item?)!
407 }
408
409 // createNewAdmin creates a new Admin resource
410 //
411 pub fun createNewAdmin(): @Admin {
412 return <-create Admin()
413 }
414 }
415
416 // -----------------------------------------------------------------------
417 // SGKCLDRAAAB contract-level function definitions
418 // -----------------------------------------------------------------------
419
420 // createEmptyCollection creates a new, empty Collection object so that
421 // a user can store it in their account storage.
422 // Once they have a Collection in their storage, they are able to receive
423 // Collectibles in transactions.
424 //
425 pub fun createEmptyCollection(): @NonFungibleToken.Collection {
426 return <-create SGKCLDRAAAB.Collection()
427 }
428
429 // getNumCollectiblesInItem return the number of Collectibles that have been
430 // minted from a certain Item.
431 //
432 // Parameters: itemID: The id of the Item that is being searched
433 //
434 // Returns: The total number of Collectibles
435 // that have been minted from a Item
436 pub fun getNumCollectiblesInItem(itemID: UInt32): UInt32 {
437 let item = (&SGKCLDRAAAB.items[itemID] as &Item?)!
438 return item.numberMintedPerItem
439 }
440
441 // -----------------------------------------------------------------------
442 // SGKCLDRAAAB initialization function
443 // -----------------------------------------------------------------------
444 //
445 init() {
446 // Initialize contract fields
447 self.items <- {}
448 self.nextItemID = 1
449 self.totalSupply = 0
450
451 self.collectionStoragePath = /storage/SGKCLDRAAABCollection
452 self.collectionPublicPath = /public/SGKCLDRAAABCollection
453 self.collectionPrivatePath = /private/SGKCLDRAAABCollection
454 self.adminStoragePath = /storage/SGKCLDRAAABAdmin
455 self.saleCollectionStoragePath = /storage/SGKCLDRAAABSaleCollection
456 self.saleCollectionPublicPath = /public/SGKCLDRAAABSaleCollection
457
458 // Put a new Collection in storage
459 self.account.save<@Collection>(<- create Collection(), to: self.collectionStoragePath)
460
461 // Create a public capability for the Collection
462 self.account.link<&{CollectionPublic}>(self.collectionPublicPath, target: self.collectionStoragePath)
463
464 // Put the Admin in storage
465 self.account.save<@Admin>(<- create Admin(), to: self.adminStoragePath)
466
467 emit ContractInitialized()
468 }
469}