Smart Contract
FindViews
A.097bafa4e0b48eef.FindViews
1import NonFungibleToken from 0x1d7e57aa55817448
2import FungibleToken from 0xf233dcee88fe0abe
3import MetadataViews from 0x1d7e57aa55817448
4import ViewResolver from 0x1d7e57aa55817448
5
6access(all) contract FindViews {
7
8 access(all) struct OnChainFile : MetadataViews.File{
9 access(all) let content: String
10 access(all) let mediaType: String
11 access(all) let protocol: String
12
13 init(content:String, mediaType: String) {
14 self.content=content
15 self.protocol="onChain"
16 self.mediaType=mediaType
17 }
18
19 access(all) view fun uri(): String {
20 return "data:".concat(self.mediaType).concat(",").concat(self.content)
21 }
22 }
23
24 access(all) struct SharedMedia : MetadataViews.File {
25 access(all) let mediaType: String
26 access(all) let pointer: ViewReadPointer
27 access(all) let protocol: String
28
29 init(pointer: ViewReadPointer, mediaType: String) {
30 self.pointer=pointer
31 self.mediaType=mediaType
32 self.protocol="shared"
33
34 if pointer.resolveView(Type<OnChainFile>()) == nil {
35 panic("Cannot create shared media if the pointer does not contain StringMedia")
36 }
37 }
38
39 // todo: this is not working so we have a workaround in the contract
40 access(all) view fun uri(): String {
41 return "data:".concat(self.mediaType).concat(",").concat(self.protocol)
42 }
43 }
44
45 access(all) resource interface VaultViews {
46 access(all) var balance: UFix64
47 access(all) view fun getViews() : [Type]
48 access(all) fun resolveView(_ view: Type): AnyStruct?
49 }
50
51 access(all) struct FTVaultData {
52 access(all) let tokenAlias: String
53 access(all) let storagePath: StoragePath
54 access(all) let receiverPath: PublicPath
55 access(all) let balancePath: PublicPath
56 access(all) let providerPath: PrivatePath
57 access(all) let vaultType: Type
58 access(all) let receiverType: Type
59 access(all) let balanceType: Type
60 access(all) let providerType: Type
61 access(all) let createEmptyVault: (fun(): @{FungibleToken.Vault})
62
63 init(
64 tokenAlias: String,
65 storagePath: StoragePath,
66 receiverPath: PublicPath,
67 balancePath: PublicPath,
68 providerPath: PrivatePath,
69 vaultType: Type,
70 receiverType: Type,
71 balanceType: Type,
72 providerType: Type,
73 createEmptyVault: (fun(): @{FungibleToken.Vault})
74 ) {
75 pre {
76 receiverType.isSubtype(of: Type<&{FungibleToken.Receiver}>()): "Receiver type must include FungibleToken.Receiver interfaces."
77 balanceType.isSubtype(of: Type<&{FungibleToken.Vault}>()): "Balance type must include FungibleToken.Vault interfaces."
78 providerType.isSubtype(of: Type<&{FungibleToken.Provider}>()): "Provider type must include FungibleToken.Provider interface."
79 }
80 self.tokenAlias=tokenAlias
81 self.storagePath=storagePath
82 self.receiverPath=receiverPath
83 self.balancePath=balancePath
84 self.providerPath = providerPath
85 self.vaultType=vaultType
86 self.receiverType=receiverType
87 self.balanceType=balanceType
88 self.providerType = providerType
89 self.createEmptyVault=createEmptyVault
90 }
91 }
92
93 // This is an example taken from Versus
94 access(all) struct CreativeWork {
95 access(all) let artist: String
96 access(all) let name: String
97 access(all) let description: String
98 access(all) let type: String
99
100 init(artist: String, name: String, description: String, type: String) {
101 self.artist=artist
102 self.name=name
103 self.description=description
104 self.type=type
105 }
106 }
107
108 /// A basic pointer that can resolve data and get owner/id/uuid and gype
109 access(all) struct interface Pointer {
110 access(all) let id: UInt64
111 access(all) fun resolveView(_ type: Type) : AnyStruct?
112 access(all) fun getUUID() :UInt64
113 access(all) fun getViews() : [Type]
114 access(all) fun owner() : Address
115 access(all) fun valid() : Bool
116 access(all) fun getItemType() : Type
117 access(all) fun getViewResolver() : &{ViewResolver.Resolver}
118
119 //There are just convenience functions for shared views in the standard
120 access(all) fun getRoyalty() : MetadataViews.Royalties
121 access(all) fun getTotalRoyaltiesCut() : UFix64
122
123 //Requred views
124 access(all) fun getDisplay() : MetadataViews.Display
125 access(all) fun getNFTCollectionData() : MetadataViews.NFTCollectionData
126
127 access(all) fun checkSoulBound() : Bool
128
129 }
130
131 //An interface to say that this pointer can withdraw
132 access(all) struct interface AuthPointer {
133 access(all) fun withdraw() : @AnyResource
134 }
135
136 access(all) struct ViewReadPointer : Pointer {
137 access(self) let cap: Capability<&{ViewResolver.ResolverCollection}>
138 access(all) let id: UInt64
139 access(all) let uuid: UInt64
140 access(all) let itemType: Type
141
142 init(cap: Capability<&{ViewResolver.ResolverCollection}>, id: UInt64) {
143 self.cap=cap
144 self.id=id
145
146 if !self.cap.check() {
147 panic("The capability is not valid.")
148 }
149 let viewResolver=self.cap.borrow()!.borrowViewResolver(id: self.id)!
150 let display = MetadataViews.getDisplay(viewResolver) ?? panic("MetadataViews Display View is not implemented on this NFT.")
151 let nftCollectionData = MetadataViews.getNFTCollectionData(viewResolver) ?? panic("MetadataViews NFTCollectionData View is not implemented on this NFT.")
152 self.uuid=viewResolver.uuid
153 self.itemType=viewResolver.getType()
154 }
155
156 access(all) fun resolveView(_ type: Type) : AnyStruct? {
157 return self.getViewResolver().resolveView(type)
158 }
159
160 access(all) fun getUUID() :UInt64{
161 return self.uuid
162 }
163
164 access(all) fun getViews() : [Type]{
165 return self.getViewResolver().getViews()
166 }
167
168 access(all) fun owner() : Address {
169 return self.cap.address
170 }
171
172 access(all) fun getTotalRoyaltiesCut() :UFix64 {
173 var total=0.0
174 for royalty in self.getRoyalty().getRoyalties() {
175 total = total + royalty.cut
176 }
177 return total
178 }
179
180 access(all) fun getRoyalty() : MetadataViews.Royalties {
181 if let v = MetadataViews.getRoyalties(self.getViewResolver()) {
182 return v
183 }
184 return MetadataViews.Royalties([])
185 }
186
187 access(all) fun valid() : Bool {
188 if !self.cap.check() || self.cap.borrow()!.borrowViewResolver(id: self.id) == nil {
189 return false
190 }
191 return true
192 }
193
194 access(all) fun getItemType() : Type {
195 return self.itemType
196 }
197
198 access(all) fun getViewResolver() : &{ViewResolver.Resolver} {
199 let nft=self.cap.borrow()!.borrowViewResolver(id: self.id) ?? panic("The capability of view pointer is not linked.")
200 return nft
201
202 }
203
204 access(all) fun getDisplay() : MetadataViews.Display {
205 if let v = MetadataViews.getDisplay(self.getViewResolver()) {
206 return v
207 }
208 panic("MetadataViews Display View is not implemented on this NFT.")
209 }
210
211 access(all) fun getNFTCollectionData() : MetadataViews.NFTCollectionData {
212 if let v = MetadataViews.getNFTCollectionData(self.getViewResolver()) {
213 return v
214 }
215 panic("MetadataViews NFTCollectionData View is not implemented on this NFT.")
216 }
217
218 access(all) fun checkSoulBound() : Bool {
219 return FindViews.checkSoulBound(self.getViewResolver())
220 }
221 }
222
223
224 access(all) fun getNounce(_ viewResolver: &{ViewResolver.Resolver}) : UInt64 {
225 if let nounce = viewResolver.resolveView(Type<FindViews.Nounce>()) {
226 if let v = nounce as? FindViews.Nounce {
227 return v.nounce
228 }
229 }
230 return 0
231 }
232
233 access(all) struct AuthNFTPointer : Pointer, AuthPointer{
234 access(self) let cap: Capability<auth(NonFungibleToken.Withdraw) &{NonFungibleToken.CollectionPublic, NonFungibleToken.Provider, ViewResolver.ResolverCollection}>
235 access(all) let id: UInt64
236 access(all) let nounce: UInt64
237 access(all) let uuid: UInt64
238 access(all) let itemType: Type
239
240 init(cap: Capability<auth(NonFungibleToken.Withdraw) &{NonFungibleToken.Collection, NonFungibleToken.Provider, ViewResolver.ResolverCollection}>, id: UInt64) {
241 self.cap=cap
242 self.id=id
243
244 if !self.cap.check() {
245 panic("The capability is not valid.")
246 }
247
248 let collection = self.cap.borrow() ?? panic("could not find collection")
249 let viewResolver=collection.borrowNFT(self.id) ?? panic("could not borrow nft")
250 let display = MetadataViews.getDisplay(viewResolver) ?? panic("MetadataViews Display View is not implemented on this NFT.")
251 let nftCollectionData = MetadataViews.getNFTCollectionData(viewResolver) ?? panic("MetadataViews NFTCollectionData View is not implemented on this NFT.")
252 self.nounce=FindViews.getNounce(viewResolver)
253 self.uuid=viewResolver.uuid
254 self.itemType=viewResolver.getType()
255 }
256
257 access(all) fun getViewResolver() : &{ViewResolver.Resolver} {
258 let cap = self.cap.borrow()!
259 let viewResolver = cap.borrowNFT(self.id) ?? panic("The capability of view pointer is not linked.")
260 return viewResolver
261 }
262
263 access(all) fun resolveView(_ type: Type) : AnyStruct? {
264 return self.getViewResolver().resolveView(type)
265 }
266
267 access(all) fun getUUID() :UInt64{
268 return self.uuid
269 }
270
271 access(all) fun getViews() : [Type]{
272 return self.getViewResolver().getViews()
273 }
274
275 access(all) fun valid() : Bool {
276 if !self.cap.check() {
277 return false
278 }
279
280 let collection = self.cap.borrow()!
281
282 let collectionType=collection.getType()
283 if collectionType.isRecovered {
284 return false
285 }
286
287 let nft= collection.borrowNFT(self.id)
288
289 if nft ==nil {
290 return false
291 }
292
293 if let nounce = nft!.resolveView(Type<FindViews.Nounce>()) {
294 if let v = nounce as? FindViews.Nounce {
295 return v.nounce==self.nounce
296 }
297 }
298 return true
299 }
300
301 access(all) fun getTotalRoyaltiesCut() :UFix64 {
302 var total=0.0
303 for royalty in self.getRoyalty().getRoyalties() {
304 total = total + royalty.cut
305 }
306 return total
307 }
308
309 access(all) fun getRoyalty() : MetadataViews.Royalties {
310 if let v = MetadataViews.getRoyalties(self.getViewResolver()) {
311 return v
312 }
313 return MetadataViews.Royalties([])
314 }
315
316 access(all) fun getDisplay() : MetadataViews.Display {
317 if let v = MetadataViews.getDisplay(self.getViewResolver()) {
318 return v
319 }
320 panic("MetadataViews Display View is not implemented on this NFT.")
321 }
322
323 access(all) fun getNFTCollectionData() : MetadataViews.NFTCollectionData {
324 if let v = MetadataViews.getNFTCollectionData(self.getViewResolver()) {
325 return v
326 }
327 panic("MetadataViews NFTCollectionData View is not implemented on this NFT.")
328 }
329
330 access(all) fun withdraw() :@{NonFungibleToken.NFT} {
331 if !self.cap.check() {
332 panic("The pointer capability is invalid.")
333 }
334 return <- self.cap.borrow()!.withdraw(withdrawID: self.id)
335 }
336
337 access(all) fun deposit(_ nft: @{NonFungibleToken.NFT}){
338 if !self.cap.check(){
339 panic("The pointer capablity is invalid.")
340 }
341 self.cap.borrow()!.deposit(token: <- nft)
342 }
343
344 access(all) fun owner() : Address {
345 return self.cap.address
346 }
347
348 access(all) fun getItemType() : Type {
349 return self.itemType
350 }
351
352 access(all) fun checkSoulBound() : Bool {
353 return FindViews.checkSoulBound(self.getViewResolver())
354 }
355 }
356
357 access(all) fun createViewReadPointer(address:Address, path:PublicPath, id:UInt64) : ViewReadPointer {
358 let cap= getAccount(address).capabilities.get<&{ViewResolver.ResolverCollection}>(path)
359 let pointer= FindViews.ViewReadPointer(cap: cap, id: id)
360 return pointer
361 }
362
363 access(all) struct Nounce {
364 access(all) let nounce: UInt64
365
366 init(_ nounce: UInt64) {
367 self.nounce=nounce
368 }
369 }
370
371 access(all) struct SoulBound {
372
373 access(all) let message: String
374
375 init(_ message:String) {
376 self.message=message
377
378 }
379 }
380
381 access(all) fun checkSoulBound(_ viewResolver: &{ViewResolver.Resolver}) : Bool {
382 if let soulBound = viewResolver.resolveView(Type<FindViews.SoulBound>()) {
383 if let v = soulBound as? FindViews.SoulBound {
384 return true
385 }
386 }
387 return false
388 }
389
390 access(all) fun getDapperAddress(): Address {
391 switch FindViews.account.address.toString() {
392 case "0x097bafa4e0b48eef":
393 //mainnet
394 return 0xead892083b3e2c6c
395 case "0x35717efbbce11c74":
396 //testnet
397 return 0x82ec283f88a62e65
398 default:
399 //emulator
400 return 0x01cf0e2f2f715450
401 }
402 }
403}
404