Smart Contract
DimensionXComics
A.e3ad6030cbaff1c2.DimensionXComics
1import FungibleToken from 0xf233dcee88fe0abe
2import NonFungibleToken from 0x1d7e57aa55817448
3import MetadataViews from 0x1d7e57aa55817448
4import DimensionX from 0xe3ad6030cbaff1c2
5import ViewResolver from 0x1d7e57aa55817448
6
7access(all) contract DimensionXComics: NonFungibleToken {
8
9 access(all) var totalSupply: UInt64
10 access(all) var totalBurned: UInt64
11
12 access(all) var metadataUrl: String
13
14 access(all) event ContractInitialized()
15 access(all) event Withdraw(id: UInt64, from: Address?)
16 access(all) event Deposit(id: UInt64, to: Address?)
17 access(all) event Mint(id: UInt64)
18 access(all) event Burn(id: UInt64)
19 access(all) event TurnIn(id: UInt64, hero: UInt64)
20
21 access(all) event MinterCreated()
22
23 access(all) let CollectionStoragePath: StoragePath
24 access(all) let CollectionPublicPath: PublicPath
25 access(all) let AdminStoragePath: StoragePath
26 access(all) let MinterStoragePath: StoragePath
27
28
29 access(all) resource NFT: NonFungibleToken.NFT {
30
31 access(all) let id: UInt64
32
33 init(
34 id: UInt64
35 ) {
36 self.id = id
37 }
38
39 access(all) fun createEmptyCollection(): @{NonFungibleToken.Collection} {
40 return <-DimensionXComics.createEmptyCollection(nftType: Type<@DimensionXComics.NFT>())
41 }
42
43 access(all) view fun getViews(): [Type] {
44 return [
45 Type<MetadataViews.ExternalURL>(),
46 Type<MetadataViews.Display>(),
47 Type<MetadataViews.Royalties>(),
48 Type<MetadataViews.NFTCollectionData>(),
49 Type<MetadataViews.NFTCollectionDisplay>()
50 ]
51 }
52
53 access(all) fun resolveView(_ view: Type): AnyStruct? {
54 switch view {
55 case Type<MetadataViews.ExternalURL>():
56 return MetadataViews.ExternalURL(
57 DimensionXComics.metadataUrl.concat("comics/").concat(self.id.toString())
58 )
59 case Type<MetadataViews.Display>():
60 return MetadataViews.Display(
61 name: ("DimensionXComics #").concat(self.id.toString()),
62 description: "A Comics NFT Project with Utility in the Dimension-X Game!",
63 thumbnail: MetadataViews.HTTPFile(
64 url: DimensionXComics.metadataUrl.concat("comics/i/").concat(self.id.toString()).concat(".jpg")
65 )
66 )
67 case Type<MetadataViews.Royalties>():
68 let royalties : [MetadataViews.Royalty] = []
69 royalties.append(MetadataViews.Royalty(
70 receiver: DimensionXComics.account.capabilities.get<&{FungibleToken.Receiver}>(MetadataViews.getRoyaltyReceiverPublicPath()),
71 cut: 0.10,
72 description: "Crypthulhu royalties"))
73 return MetadataViews.Royalties(royalties)
74
75 case Type<MetadataViews.NFTCollectionData>():
76 return DimensionX.resolveContractView(resourceType: Type<@DimensionXComics.NFT>(), viewType: Type<MetadataViews.NFTCollectionData>())
77 case Type<MetadataViews.NFTCollectionDisplay>():
78 return DimensionX.resolveContractView(resourceType: Type<@DimensionXComics.NFT>(), viewType: Type<MetadataViews.NFTCollectionDisplay>())
79 case Type<MetadataViews.Serial>():
80 return MetadataViews.Serial(
81 self.id
82 )
83 }
84
85 return nil
86 }
87 }
88
89 access(all) resource interface CollectionPublic {}
90
91 access(all) resource Collection: NonFungibleToken.Collection, CollectionPublic {
92 // dictionary of NFT conforming tokens
93 // NFT is a resource type with an `UInt64` ID field
94 access(all) var ownedNFTs: @{UInt64: {NonFungibleToken.NFT}}
95
96 init () {
97 self.ownedNFTs <- {}
98 }
99
100 access(all) view fun getSupportedNFTTypes(): {Type: Bool} {
101 let supportedTypes: {Type: Bool} = {}
102 supportedTypes[Type<@DimensionXComics.NFT>()] = true
103 return supportedTypes
104 }
105
106 access(all) view fun isSupportedNFTType(type: Type): Bool {
107 return type == Type<@DimensionXComics.NFT>()
108 }
109
110 // withdraw removes an NFT from the collection and moves it to the caller
111 access(NonFungibleToken.Withdraw) fun withdraw(withdrawID: UInt64): @{NonFungibleToken.NFT} {
112
113 let token <- self.ownedNFTs.remove(key: withdrawID) ?? panic("missing NFT")
114
115 emit Withdraw(id: token.id, from: self.owner?.address)
116
117 return <-token
118 }
119
120 // deposit takes a NFT and adds it to the collections dictionary
121 // and adds the ID to the id array
122 access(all) fun deposit(token: @{NonFungibleToken.NFT}) {
123 let token <- token as! @DimensionXComics.NFT
124
125 let id: UInt64 = token.id
126
127 // add the new token to the dictionary which removes the old one
128 let oldToken <- self.ownedNFTs[id] <- token
129
130 emit Deposit(id: id, to: self.owner?.address)
131
132 destroy oldToken
133 }
134
135 // getIDs returns an array of the IDs that are in the collection
136 access(all) view fun getIDs(): [UInt64] {
137 return self.ownedNFTs.keys
138 }
139
140 // borrowNFT gets a reference to an NFT in the collection
141 // so that the caller can read its metadata and call its methods
142 access(all) view fun borrowNFT(_ id: UInt64): &{NonFungibleToken.NFT}? {
143 return (&self.ownedNFTs[id] as &{NonFungibleToken.NFT}?)!
144 }
145
146 /// Borrow the view resolver for the specified NFT ID
147 access(all) view fun borrowViewResolver(id: UInt64): &{ViewResolver.Resolver}? {
148 if let nft = &self.ownedNFTs[id] as &{NonFungibleToken.NFT}? {
149 return nft as &{ViewResolver.Resolver}
150 }
151 return nil
152 }
153
154 access(all) fun createEmptyCollection(): @{NonFungibleToken.Collection} {
155 return <-DimensionXComics.createEmptyCollection(nftType: Type<@DimensionXComics.NFT>())
156 }
157
158 access(NonFungibleToken.Withdraw) fun turnInComics(comic_ids: [UInt64], hero: &DimensionX.NFT) {
159 if (comic_ids.length > 4) {
160 panic("Too many comics being burned")
161 }
162
163 if (self.owner?.address != hero.owner?.address) {
164 panic("You must own the hero")
165 }
166
167 for id in comic_ids {
168 let token <- self.withdraw(withdrawID: id)
169 emit TurnIn(id: token.id, hero: hero.id)
170 destroy token
171 }
172 }
173 }
174
175 // public function that anyone can call to create a new empty collection
176 access(all) fun createEmptyCollection(nftType: Type): @{NonFungibleToken.Collection} {
177 return <- create Collection()
178 }
179
180 access(all) view fun getContractViews(resourceType: Type?): [Type] {
181 return [
182 Type<MetadataViews.NFTCollectionData>(),
183 Type<MetadataViews.NFTCollectionDisplay>()
184 ]
185 }
186
187 access(all) fun resolveContractView(resourceType: Type?, viewType: Type): AnyStruct? {
188 switch viewType {
189 case Type<MetadataViews.NFTCollectionData>():
190 return MetadataViews.NFTCollectionData(
191 storagePath: DimensionXComics.CollectionStoragePath,
192 publicPath: DimensionXComics.CollectionPublicPath,
193 publicCollection: Type<&DimensionXComics.Collection>(),
194 publicLinkedType: Type<&DimensionXComics.Collection>(),
195 createEmptyCollectionFunction: (fun (): @{NonFungibleToken.Collection} {
196 return <-DimensionXComics.createEmptyCollection(nftType: Type<@DimensionXComics.NFT>())
197 })
198 )
199 case Type<MetadataViews.NFTCollectionDisplay>():
200 return MetadataViews.NFTCollectionDisplay(
201 name: "Dimension X",
202 description: "Dimension X is a Free-to-Play, Play-to-Earn strategic role playing game on the Flow blockchain set in the Dimension X comic book universe, where a pan-dimensional explosion created super powered humans, aliens and monsters with radical and terrifying superpowers!",
203 externalURL: MetadataViews.ExternalURL("https://dimensionxnft.com"),
204 squareImage: MetadataViews.Media(
205 file: MetadataViews.HTTPFile(url: DimensionXComics.metadataUrl.concat("comics/collection_image.png")),
206 mediaType: "image/png"
207 ),
208 bannerImage: MetadataViews.Media(
209 file: MetadataViews.HTTPFile(url: DimensionXComics.metadataUrl.concat("comics/collection_banner.png")),
210 mediaType: "image/png"
211 ),
212 socials: {
213 "discord": MetadataViews.ExternalURL("https://discord.gg/dimensionx"),
214 "twitter": MetadataViews.ExternalURL("https://twitter.com/DimensionX_NFT")
215 }
216 )
217 }
218 return nil
219 }
220
221 // Resource that an admin or something similar would own to be
222 // able to mint new NFTs
223 //
224 access(all) resource NFTMinter {
225 // range if possible
226
227 // Determine the next available ID for the rest of NFTs and take into
228 // account the custom NFTs that have been minted outside of the reserved
229 // range
230 access(all) fun getNextID(): UInt64 {
231
232 return DimensionXComics.totalSupply + UInt64(1)
233 }
234
235 access(all) fun mintNFT(
236 recipient: &DimensionXComics.Collection,
237 ) {
238 // Determine the next available ID
239 var nextId = self.getNextID()
240
241 // Update supply counters
242 DimensionXComics.totalSupply = DimensionXComics.totalSupply + UInt64(1)
243
244 self.mint(
245 recipient: recipient,
246 id: nextId
247 )
248 }
249
250 access(self) fun mint(
251 recipient: &DimensionXComics.Collection,
252 id: UInt64
253 ) {
254 // create a new NFT
255 var newNFT <- create NFT(id: id)
256 emit Mint(id: id)
257
258 // deposit it in the recipient's account using their reference
259 recipient.deposit(token: <-newNFT)
260 }
261 }
262
263 access(all) resource Admin {
264
265
266 access(all) fun setMetadataUrl(url: String) {
267 DimensionXComics.metadataUrl = url
268 }
269
270 access(all) fun createNFTMinter(): @NFTMinter {
271 emit MinterCreated()
272 return <-create NFTMinter()
273 }
274
275 }
276
277 init() {
278 // Initialize supply counters
279 self.totalSupply = 0
280
281 // Initialize burned counters
282 self.totalBurned = 0
283
284 self.metadataUrl = "https://metadata.dimensionx.com/"
285
286
287
288 // Set the named paths
289 self.CollectionStoragePath = /storage/dmxComicsCollection
290 self.CollectionPublicPath = /public/dmxComicsCollection
291 self.AdminStoragePath = /storage/dmxComicsAdmin
292 self.MinterStoragePath = /storage/dmxComicsMinter
293
294 // Create a Collection resource and save it to storage
295 let collection <- create Collection()
296 self.account.storage.save(<-collection, to: self.CollectionStoragePath)
297
298 // create a public capability for the collection
299 let collectionCap = self.account.capabilities.storage.issue<&DimensionXComics.Collection>(self.CollectionStoragePath)
300 self.account.capabilities.publish(collectionCap, at: self.CollectionPublicPath)
301
302 let admin <- create Admin()
303 let minter <- admin.createNFTMinter()
304 self.account.storage.save(<-admin, to: self.AdminStoragePath)
305 self.account.storage.save(<-minter, to: self.MinterStoragePath)
306
307 emit ContractInitialized()
308 }
309}
310