Smart Contract
GenerativeNFTV3
A.0b80e42aaab305f0.GenerativeNFTV3
1import NonFungibleToken from 0x1d7e57aa55817448
2import MetadataViews from 0x1d7e57aa55817448
3
4pub contract GenerativeNFTV3: NonFungibleToken {
5
6 pub var totalSupply: UInt64
7 pub var maxSupply: UInt64
8 pub let nftData: {UInt64: {String:String}}
9
10 //------------------------------------------------------------
11 // Events
12 //------------------------------------------------------------
13 pub event ContractInitialized()
14 pub event Withdraw(id: UInt64, from: Address?)
15 pub event Deposit(id: UInt64, to: Address?)
16 pub event Minted(id: UInt64, initMeta: {String: String})
17
18 //------------------------------------------------------------
19 // Storage Path
20 //------------------------------------------------------------
21 pub let CollectionStoragePath: StoragePath
22 pub let CollectionPublicPath: PublicPath
23 pub let MinterStoragePath: StoragePath
24
25 // idToAddress
26 // Maps each item ID to its current owner
27 access(self) let idToAddress: {UInt64: Address}
28
29
30 //------------------------------------------------------------
31 // NFT Resource
32 //------------------------------------------------------------
33 pub resource NFT: NonFungibleToken.INFT, MetadataViews.Resolver {
34 pub let id: UInt64
35 access(self) let metadata: {String: String}
36
37 init(initID: UInt64, initMeta: {String: String}) {
38 self.id = initID
39 self.metadata = initMeta
40 }
41
42 pub fun getMetadata(): {String: String} {
43 return self.metadata
44 }
45
46 pub fun getImage() : String {
47 return self.getMetadata()["image"] ?? ""
48 }
49
50 pub fun getTitle() : String {
51 return self.getMetadata()["title"] ?? ""
52 }
53
54 pub fun getDescription() : String {
55 return self.getMetadata()["description"] ?? ""
56 }
57
58 // receiver: Capability<&AnyResource{FungibleToken.Receiver}>, cut: UFix64, description: String
59 pub fun getRoyalties():MetadataViews.Royalties {
60 return MetadataViews.Royalties([
61
62 ])
63 }
64
65 /// Function that returns all the Metadata Views implemented by a Non Fungible Token
66 ///
67 /// @return An array of Types defining the implemented views. This value will be used by
68 /// developers to know which parameter to pass to the resolveView() method.
69 ///
70 pub fun getViews(): [Type] {
71 return [
72 Type<MetadataViews.Display>(),
73 Type<MetadataViews.Royalties>(),
74 Type<MetadataViews.ExternalURL>(),
75 Type<MetadataViews.NFTCollectionData>(),
76 Type<MetadataViews.NFTCollectionDisplay>(),
77 Type<MetadataViews.Serial>()
78 ]
79 }
80
81 pub fun resolveView(_ view: Type): AnyStruct? {
82 switch view {
83 case Type<MetadataViews.Display>():
84 return MetadataViews.Display(
85 name: self.getTitle(),
86 description: self.getDescription(),
87 thumbnail: MetadataViews.HTTPFile(
88 url: self.getImage()
89 )
90 )
91 case Type<MetadataViews.Serial>():
92 return MetadataViews.Serial(
93 self.id
94 )
95 case Type<MetadataViews.Royalties>():
96 return self.getRoyalties()
97 case Type<MetadataViews.ExternalURL>():
98 return MetadataViews.ExternalURL("https://mikosea.io/")
99 case Type<MetadataViews.NFTCollectionData>():
100 return MetadataViews.NFTCollectionData(
101 storagePath: GenerativeNFTV3.CollectionStoragePath,
102 publicPath: GenerativeNFTV3.CollectionPublicPath,
103 providerPath: /private/MiKoSeaNFTCollection,
104 publicCollection: Type<&GenerativeNFTV3.Collection{GenerativeNFTV3.GenerativeNFTCollectionPublic}>(),
105 publicLinkedType: Type<&GenerativeNFTV3.Collection{GenerativeNFTV3.GenerativeNFTCollectionPublic,NonFungibleToken.CollectionPublic,NonFungibleToken.Receiver,MetadataViews.ResolverCollection}>(),
106 providerLinkedType: Type<&GenerativeNFTV3.Collection{GenerativeNFTV3.GenerativeNFTCollectionPublic,NonFungibleToken.CollectionPublic,NonFungibleToken.Provider,MetadataViews.ResolverCollection}>(),
107 createEmptyCollectionFunction: (fun (): @NonFungibleToken.Collection {
108 return <-GenerativeNFTV3.createEmptyCollection()
109 })
110 )
111 case Type<MetadataViews.NFTCollectionDisplay>():
112 let bannerImage = MetadataViews.Media(
113 file: MetadataViews.HTTPFile(
114 url: "https://storage.googleapis.com/studio-design-asset-files/projects/1pqD36e6Oj/s-300x50_aa59a692-741b-408b-aea3-bcd25d29c6bd.svg"
115 ),
116 mediaType: "image/svg+xml"
117 )
118 let squareImage = MetadataViews.Media(
119 file: MetadataViews.HTTPFile(
120 url: "https://app.mikosea.io/mikosea_1.png"
121 ),
122 mediaType: "image/png"
123 )
124 return MetadataViews.NFTCollectionDisplay(
125 name: "あらゆる事業者の思いを載せて神輿を担ぐNFTクラウドファンディングマーケット",
126 description: "MikoSeaはアーティスト、企業、インフルエンサーといったクリエイターや、あたらしく何かを始めたい人のためのクラウドファンディングサービスです。プロジェクトの発起人は、NFTを販売することで商品を販売するという一方向の取引を超え、プロジェクトの想いに共感した”熱狂的なファン”から資金を調達し、夢の実現へと近づけます。プロジェクト支援者は、プロジェクトを支援する目的でNFTを購入し、共創・協働のプロセスに参加することで、プロジェクトから特別な体験価値やメリットを得ることができます。",
127 externalURL: MetadataViews.ExternalURL("https://app.mikosea.io/"),
128 squareImage: squareImage,
129 bannerImage: bannerImage,
130 socials: {
131 "twitter": MetadataViews.ExternalURL("https://twitter.com/MikoSea_io")
132 }
133 )
134 }
135 return nil
136 }
137 }
138
139 //------------------------------------------------------------
140 // Collection Public Interface
141 //------------------------------------------------------------
142
143 pub resource interface GenerativeNFTCollectionPublic {
144 pub fun deposit(token: @NonFungibleToken.NFT)
145 pub fun getIDs(): [UInt64]
146 pub fun borrowViewResolver(id: UInt64): &{MetadataViews.Resolver}
147 pub fun borrowNFT(id: UInt64): &NonFungibleToken.NFT
148 pub fun borrowItem(id: UInt64): &GenerativeNFTV3.NFT? {
149 post {
150 (result == nil) || (result?.id == id):
151 "Cannot borrow reference: The ID of the returned reference is incorrect"
152 }
153 }
154 }
155
156 //------------------------------------------------------------
157 // Collection Resource
158 //------------------------------------------------------------
159
160 pub resource Collection: GenerativeNFTCollectionPublic, NonFungibleToken.Provider, NonFungibleToken.Receiver, NonFungibleToken.CollectionPublic, MetadataViews.ResolverCollection {
161
162 pub var ownedNFTs: @{UInt64: NonFungibleToken.NFT}
163
164 init () {
165 self.ownedNFTs <- {}
166 }
167
168 pub fun withdraw(withdrawID: UInt64): @NonFungibleToken.NFT {
169 let token <- self.ownedNFTs.remove(key: withdrawID) ?? panic("missing NFT")
170 emit Withdraw(id: token.id, from: self.owner!.address)
171 return <-token
172 }
173
174 pub fun deposit(token: @NonFungibleToken.NFT) {
175 let token <- token as! @GenerativeNFTV3.NFT
176 let id: UInt64 = token.id
177 let oldToken <- self.ownedNFTs[id] <- token
178 // update owner
179
180 if self.owner?.address != nil {
181 GenerativeNFTV3.idToAddress[id] = self.owner!.address
182 emit Deposit(id: id, to: self.owner!.address)
183 }
184 destroy oldToken
185 }
186
187 pub fun transfer(id: UInt64, recipient: &{NonFungibleToken.CollectionPublic}) {
188 post {
189 self.ownedNFTs[id] == nil: "The specified NFT was not transferred"
190 recipient.borrowNFT(id: id) != nil: "Recipient did not receive the intended NFT"
191 }
192 let nft <- self.withdraw(withdrawID: id)
193 recipient.deposit(token: <- nft)
194 }
195
196 pub fun burn(id: UInt64) {
197 post {
198 self.ownedNFTs[id] == nil: "The specified NFT was not burned"
199 }
200 destroy <- self.withdraw(withdrawID: id)
201 }
202
203 pub fun getIDs(): [UInt64] {
204 return self.ownedNFTs.keys
205 }
206
207 pub fun borrowNFT(id: UInt64): &NonFungibleToken.NFT {
208 if self.ownedNFTs[id] != nil {
209 return (&self.ownedNFTs[id] as &NonFungibleToken.NFT?)!
210 }
211 panic("NFT not found in collection.")
212 }
213
214 pub fun borrowItem(id: UInt64): &GenerativeNFTV3.NFT? {
215 if self.ownedNFTs[id] != nil {
216 let ref = &self.ownedNFTs[id] as auth &NonFungibleToken.NFT?
217 if ref != nil {
218 return ref! as! &GenerativeNFTV3.NFT
219 }
220 }
221 return nil
222 }
223
224 pub fun borrowViewResolver(id: UInt64): &AnyResource{MetadataViews.Resolver} {
225 let nft = (&self.ownedNFTs[id] as auth &NonFungibleToken.NFT?)!
226 let mikoseaNFT = nft as! &GenerativeNFTV3.NFT
227 return mikoseaNFT as &AnyResource{MetadataViews.Resolver}
228 }
229
230 /// Safe way to borrow a reference to an NFT that does not panic
231 ///
232 /// @param id: The ID of the NFT that want to be borrowed
233 /// @return An optional reference to the desired NFT, will be nil if the passed id does not exist
234 ///
235 pub fun borrowNFTSafe(id: UInt64): &GenerativeNFTV3.NFT? {
236 return self.borrowItem(id: id)
237 }
238
239 destroy() {
240 destroy self.ownedNFTs
241 }
242 }
243
244 // createEmptyCollection
245 pub fun createEmptyCollection(): @NonFungibleToken.Collection {
246 return <- create Collection()
247 }
248
249 //------------------------------------------------------------
250 // NFT Minter
251 //------------------------------------------------------------
252 pub resource NFTMinter {
253
254 pub fun mintNFTs(initMetadata: {String: String}): @GenerativeNFTV3.NFT{
255 pre{
256 GenerativeNFTV3.totalSupply < GenerativeNFTV3.maxSupply : "NFT Sold Out!!!"
257 }
258 GenerativeNFTV3.totalSupply = GenerativeNFTV3.totalSupply + 1
259 let nftID = GenerativeNFTV3.totalSupply
260 var newNFT <- create GenerativeNFTV3.NFT(
261 initID: nftID, initMeta: initMetadata
262 )
263 GenerativeNFTV3.nftData[nftID] = initMetadata
264 emit Minted(id: nftID, initMeta: initMetadata)
265 return <- newNFT
266 }
267
268 pub fun mintNFT(initMetadata: {String: String}, address: Address): @GenerativeNFTV3.NFT {
269 let newNFT <- self.mintNFTs(initMetadata: initMetadata)
270 GenerativeNFTV3.idToAddress[newNFT.id] = address
271 return <- newNFT
272 }
273
274 pub fun addSuply(num: UInt64) {
275 GenerativeNFTV3.maxSupply = GenerativeNFTV3.maxSupply + num
276 }
277 }
278
279 // getOwner
280 // Gets the current owner of the given item
281 //
282 pub fun getOwner(itemID: UInt64): Address? {
283 if itemID >= 0 && itemID < self.maxSupply {
284 if (itemID < GenerativeNFTV3.totalSupply) {
285 return GenerativeNFTV3.idToAddress[itemID]
286 } else {
287 return nil
288 }
289 }
290 return nil
291 }
292
293 //------------------------------------------------------------
294 // Initializer
295 //------------------------------------------------------------
296 init() {
297 // Set our named paths
298 self.CollectionStoragePath = /storage/GenerativeNFTV3Collections
299 self.CollectionPublicPath = /public/GenerativeNFTV3Collections
300 self.MinterStoragePath = /storage/GenerativeNFTV3Minters
301
302 // Initialize the total supply
303 self.totalSupply = 0
304
305 // Initialize the max supply
306 self.maxSupply = 10000
307
308 // Initalize mapping from ID to address
309 self.idToAddress = {}
310
311 self.nftData = {}
312
313 // Create a Minter resource and save it to storage
314 let minter <- create NFTMinter()
315 self.account.save(<-minter, to: self.MinterStoragePath)
316 emit ContractInitialized()
317 }
318}
319