Smart Contract
RCRDSHPNFT
A.6c3ff40b90b928ab.RCRDSHPNFT
1import NonFungibleToken from 0x1d7e57aa55817448
2import MetadataViews from 0x1d7e57aa55817448
3
4pub contract RCRDSHPNFT: NonFungibleToken {
5 pub var totalSupply: UInt64
6 pub let minterStoragePath: StoragePath
7 pub let collectionStoragePath: StoragePath
8 pub let collectionPublicPath: PublicPath
9
10 pub event ContractInitialized()
11 pub event Withdraw(id: UInt64, from: Address?)
12 pub event Deposit(id: UInt64, to: Address?)
13 pub event Burn(id: UInt64, from: Address?)
14 pub event Sale(id: UInt64, price: UInt64)
15
16 pub resource NFT: NonFungibleToken.INFT, MetadataViews.Resolver {
17 pub let id: UInt64
18 pub var metadata: {String: String}
19
20 pub fun getViews(): [Type] {
21 return [
22 Type<MetadataViews.Serial>(),
23 Type<MetadataViews.Display>(),
24 Type<MetadataViews.ExternalURL>(),
25 Type<MetadataViews.NFTCollectionData>(),
26 Type<MetadataViews.NFTCollectionDisplay>(),
27 Type<MetadataViews.Royalties>(),
28 Type<MetadataViews.Traits>()
29 ]
30 }
31
32
33
34 pub fun resolveView(_ view: Type): AnyStruct? {
35
36 let metadata = self.metadata
37
38 fun getMetaValue(_ key: String, _ defaultVal: String) : String {
39 return metadata[key] ?? defaultVal
40 }
41
42 fun getThumbnail(): MetadataViews.HTTPFile {
43 let url = metadata["uri"] == nil ? "https://rcrdshp-happyfox-assets.s3.amazonaws.com/Purple.svg" : metadata["uri"]!.concat("/thumbnail")
44 return MetadataViews.HTTPFile(url: url)
45 }
46
47 fun createGenericDisplay(): MetadataViews.Display {
48 let name = getMetaValue("name", "?RCRDSHP NFT?")
49 let serial = getMetaValue("serial_number", "?")
50 return MetadataViews.Display(
51 name: name,
52 description: getMetaValue("description", "An unknown RCRDSHP Collection NFT"),
53 thumbnail: getThumbnail()
54 )
55 }
56
57 fun createVoucherDisplay(): MetadataViews.Display {
58 let name = getMetaValue("name", "?RCRDSHP Voucher NFT?")
59 let serial = getMetaValue("voucher_serial_number", "?")
60 let isFlowFest = name.slice(from: 0, upTo: 9) == "Flow fest"
61 return MetadataViews.Display(
62 name: name.concat(" #").concat(serial),
63 description: getMetaValue("description", "An unknown RCRDSHP Collection Vouncher NFT"),
64 thumbnail: isFlowFest ? MetadataViews.HTTPFile(url: "https://rcrdshp-happyfox-assets.s3.amazonaws.com/flowfest-pack.png") : getThumbnail()
65 )
66 }
67
68 fun createTraits(): MetadataViews.Traits {
69 let rarity = metadata["rarity"]
70 if rarity == nil{
71 return MetadataViews.Traits(traits: [])
72 } else {
73 let rarityTrait = MetadataViews.Trait(
74 name: "Rarity",
75 value: rarity!,
76 rarity: nil,
77 displayType: nil
78 )
79 return MetadataViews.Traits(traits: [rarityTrait])
80 }
81 }
82
83 fun createExternalURL(): MetadataViews.ExternalURL {
84 return MetadataViews.ExternalURL(url: metadata["uri"] ?? "https://app.rcrdshp.com")
85 }
86
87 fun createCollectionData(): MetadataViews.NFTCollectionData {
88 return MetadataViews.NFTCollectionData(
89 storagePath: RCRDSHPNFT.collectionStoragePath,
90 publicPath: RCRDSHPNFT.collectionPublicPath,
91 providerPath: /private/RCRDSHPNFTCollection,
92 publicCollection: Type<&RCRDSHPNFT.Collection{RCRDSHPNFT.RCRDSHPNFTCollectionPublic}>(),
93 publicLinkedType: Type<&RCRDSHPNFT.Collection{RCRDSHPNFT.RCRDSHPNFTCollectionPublic,NonFungibleToken.CollectionPublic,NonFungibleToken.Receiver,MetadataViews.ResolverCollection}>(),
94 providerLinkedType: Type<&RCRDSHPNFT.Collection{RCRDSHPNFT.RCRDSHPNFTCollectionPublic,NonFungibleToken.CollectionPublic,NonFungibleToken.Provider,MetadataViews.ResolverCollection}>(),
95 createEmptyCollectionFunction: (fun (): @NonFungibleToken.Collection {
96 return <-RCRDSHPNFT.createEmptyCollection()
97 })
98 )
99 }
100
101 fun createCollectionDisplay(): MetadataViews.NFTCollectionDisplay {
102 let squareMedia = MetadataViews.Media(
103 file: MetadataViews.HTTPFile(
104 url: "https://rcrdshp-happyfox-assets.s3.amazonaws.com/Purple.svg"
105 ),
106 mediaType: "image/svg+xml"
107 )
108 let bannerMedia = MetadataViews.Media(
109 file: MetadataViews.HTTPFile(
110 url: "https://rcrdshp-happyfox-assets.s3.amazonaws.com/banner.png"
111 ),
112 mediaType: "image/png"
113 )
114
115 return MetadataViews.NFTCollectionDisplay(
116 name: "The RCRDSHP Collection",
117 description: "Here comes the drop!",
118 externalURL: MetadataViews.ExternalURL("https://app.rcrdshp.com"),
119 squareImage: squareMedia,
120 bannerImage: bannerMedia,
121 socials: {
122 "twitter": MetadataViews.ExternalURL("https://twitter.com/rcrdshp"),
123 "instagram": MetadataViews.ExternalURL("https://www.instagram.com/rcrdshp"),
124 "discord": MetadataViews.ExternalURL("https://discord.gg/rcrdshp"),
125 "facebook": MetadataViews.ExternalURL("https://www.facebook.com/rcrdshp")
126 }
127 )
128 }
129
130 fun createRoyalties(): MetadataViews.Royalties {
131 let royalties : [MetadataViews.Royalty] = []
132 return MetadataViews.Royalties(royalties: royalties)
133 }
134
135 fun parseUInt64(_ string: String) : UInt64? {
136 let chars : {Character : UInt64} = {
137 "0" : 0 ,
138 "1" : 1 ,
139 "2" : 2 ,
140 "3" : 3 ,
141 "4" : 4 ,
142 "5" : 5 ,
143 "6" : 6 ,
144 "7" : 7 ,
145 "8" : 8 ,
146 "9" : 9
147 }
148 var number : UInt64 = 0
149 var i = 0
150 while i < string.length {
151 if let n = chars[string[i]] {
152 number = number * 10 + n
153 } else {
154 return nil
155 }
156 i = i + 1
157 }
158 return number
159 }
160
161
162 switch view {
163 case Type<MetadataViews.Serial>():
164 return MetadataViews.Serial(parseUInt64(getMetaValue("serial_number", "0")) ?? 0)
165 case Type<MetadataViews.Display>():
166 return metadata["type"] == "Voucher" ? createVoucherDisplay() : createGenericDisplay()
167 case Type<MetadataViews.ExternalURL>():
168 return createExternalURL()
169 case Type<MetadataViews.NFTCollectionData>():
170 return createCollectionData()
171 case Type<MetadataViews.NFTCollectionDisplay>():
172 return createCollectionDisplay()
173 case Type<MetadataViews.Royalties>():
174 return createRoyalties()
175 case Type<MetadataViews.Traits>():
176 return createTraits()
177 }
178 return nil
179 }
180
181 init(initID: UInt64, metadata: {String : String}) {
182 self.id = initID
183 self.metadata = metadata
184 }
185 }
186
187 pub resource interface RCRDSHPNFTCollectionPublic {
188 pub fun deposit(token: @NonFungibleToken.NFT)
189 pub fun getIDs(): [UInt64]
190 pub fun borrowNFT(id: UInt64): &NonFungibleToken.NFT
191 pub fun borrowRCRDSHPNFT(id: UInt64): &RCRDSHPNFT.NFT? {
192 post {
193 (result == nil) || (result?.id == id):
194 "Cannot borrow RCRDSHPNFT reference: the ID of the returned reference is incorrect"
195 }
196 }
197 }
198
199 pub resource Collection: RCRDSHPNFTCollectionPublic, NonFungibleToken.Provider, NonFungibleToken.Receiver, NonFungibleToken.CollectionPublic, MetadataViews.ResolverCollection {
200 pub var ownedNFTs: @{UInt64: NonFungibleToken.NFT}
201
202 init () {
203 self.ownedNFTs <- {}
204 }
205
206 pub fun withdraw(withdrawID: UInt64): @NonFungibleToken.NFT {
207 let token <- self.ownedNFTs.remove(key: withdrawID) ?? panic("withdraw - missing NFT")
208
209 emit Withdraw(id: token.id, from: self.owner?.address)
210 return <-token
211 }
212
213 pub fun deposit(token: @NonFungibleToken.NFT) {
214 let token <- token as! @RCRDSHPNFT.NFT
215 let id: UInt64 = token.id
216 let oldToken <- self.ownedNFTs[id] <- token
217
218 emit Deposit(id: id, to: self.owner?.address)
219 destroy oldToken
220 }
221
222 pub fun sale(id: UInt64, price: UInt64): @NonFungibleToken.NFT {
223 emit Sale(id: id, price: price)
224 return <-self.withdraw(withdrawID: id)
225 }
226
227 pub fun burn(burnID: UInt64){
228 let token <- self.ownedNFTs.remove(key: burnID) ?? panic("burn - missing NFT")
229
230 emit Burn(id: token.id, from: self.owner?.address)
231 destroy token
232 }
233
234 pub fun getIDs(): [UInt64] {
235 return self.ownedNFTs.keys
236 }
237
238 pub fun borrowNFT(id: UInt64): &NonFungibleToken.NFT {
239 return (&self.ownedNFTs[id] as &NonFungibleToken.NFT?)!
240 }
241
242 pub fun borrowRCRDSHPNFT(id: UInt64): &RCRDSHPNFT.NFT? {
243 if self.ownedNFTs[id] != nil {
244 let ref = &self.ownedNFTs[id] as auth &NonFungibleToken.NFT?
245 return ref as! &RCRDSHPNFT.NFT?
246 }
247
248 return nil
249 }
250
251 pub fun borrowViewResolver(id: UInt64): &AnyResource{MetadataViews.Resolver} {
252 let nft = (&self.ownedNFTs[id] as auth &NonFungibleToken.NFT?)!
253 let rcrdshpNFT = nft as! &RCRDSHPNFT.NFT
254 return rcrdshpNFT as &AnyResource{MetadataViews.Resolver}
255 }
256
257 destroy() {
258 destroy self.ownedNFTs
259 }
260 }
261
262 pub fun createEmptyCollection(): @NonFungibleToken.Collection {
263 return <- create Collection()
264 }
265
266 pub resource NFTMinter {
267 pub fun mintNFT(recipient: &{NonFungibleToken.CollectionPublic}, meta: {String : String}) {
268 var newNFT <- create NFT(initID: RCRDSHPNFT.totalSupply, metadata: meta)
269 recipient.deposit(token: <-newNFT)
270 RCRDSHPNFT.totalSupply = RCRDSHPNFT.totalSupply + UInt64(1)
271 }
272 }
273
274 init() {
275 self.totalSupply = 0
276
277 self.minterStoragePath = /storage/RCRDSHPNFTMinter
278 self.collectionStoragePath = /storage/RCRDSHPNFTCollection
279 self.collectionPublicPath = /public/RCRDSHPNFTCollection
280
281 let collection <- create Collection()
282 self.account.save(<-collection, to: self.collectionStoragePath)
283
284 self.account.link<&RCRDSHPNFT.Collection{NonFungibleToken.CollectionPublic, RCRDSHPNFT.RCRDSHPNFTCollectionPublic}>(
285 self.collectionPublicPath,
286 target: self.collectionStoragePath
287 )
288
289 let minter <- create NFTMinter()
290 self.account.save(<-minter, to: self.minterStoragePath)
291
292 emit ContractInitialized()
293 }
294}
295