Smart Contract

FTViewUtils

A.15a918087ab12d86.FTViewUtils

Valid From

86,824,207

Deployed

3d ago
Feb 24, 2026, 11:41:43 PM UTC

Dependents

3 imports
1/**
2> Author: Fixes Lab <https://github.com/fixes-world/>
3
4# Token List - A on-chain list of Flow Standard Fungible Tokens (FTs).
5
6This is the Fungible Token view utilties contract of the Token List.
7
8*/
9import MetadataViews from 0x1d7e57aa55817448
10import ViewResolver from 0x1d7e57aa55817448
11import FungibleToken from 0xf233dcee88fe0abe
12import FungibleTokenMetadataViews from 0xf233dcee88fe0abe
13
14access(all) contract FTViewUtils {
15
16    // ----- Entitlement -----
17
18    // An entitlement for allowing edit the FT View Data
19    access(all) entitlement Editable
20
21    /*  ---- Events ---- */
22
23    access(all) event FTViewStoragePathUpdated(
24        address: Address,
25        contractName: String,
26        storagePath: StoragePath
27    )
28
29    access(all) event FTVaultDataUpdated(
30        address: Address,
31        contractName: String,
32        storagePath: StoragePath,
33        receiverPath: PublicPath,
34        metadataPath: PublicPath,
35        receiverType: Type,
36        metadataType: Type
37    )
38
39    access(all) event FTDisplayUpdated(
40        address: Address,
41        contractName: String,
42        name: String?,
43        symbol: String?,
44        description: String?,
45        externalURL: String?,
46        logo: String?,
47        socials: {String: String}
48    )
49
50    /// The struct interface for the Fungible Token Identity
51    ///
52    access(all) struct interface TokenIdentity {
53        /// Build type
54        access(all)
55        view fun buildType(): Type
56        /// Get Type identifier
57        access(all)
58        view fun toString(): String {
59            return self.buildType().identifier
60        }
61    }
62
63    /// The struct for the Fungible Token Identity
64    ///
65    access(all) struct FTIdentity: TokenIdentity {
66        access(all)
67        let address: Address
68        access(all)
69        let contractName: String
70
71        view init(
72            _ address: Address,
73            _ contractName: String
74        ) {
75            self.address = address
76            self.contractName = contractName
77        }
78
79        access(all)
80        view fun buildType(): Type {
81            return FTViewUtils.buildFTVaultType(self.address, self.contractName)
82                ?? panic("Could not build the FT Type")
83        }
84
85        /// Borrow the Fungible Token Contract
86        ///
87        access(all)
88        fun borrowFungibleTokenContract(): &{FungibleToken} {
89            return getAccount(self.address)
90                .contracts.borrow<&{FungibleToken}>(name: self.contractName)
91                ?? panic("Could not borrow the FungibleToken contract reference")
92        }
93    }
94
95    /// The struct for the Fungible Token Vault Data with Source
96    ///
97    access(all) struct FTVaultDataWithSource {
98        access(all)
99        let source: Address?
100        access(all)
101        let vaultData: FungibleTokenMetadataViews.FTVaultData
102
103        view init(
104            _ source: Address?,
105            _ vaultData: FungibleTokenMetadataViews.FTVaultData
106        ) {
107            self.source = source
108            self.vaultData = vaultData
109        }
110    }
111
112    /// The struct for the Fungible Token Display with Source
113    ///
114    access(all) struct FTDisplayWithSource {
115        access(all)
116        let source: Address?
117        access(all)
118        let display: FungibleTokenMetadataViews.FTDisplay
119
120        view init(
121            _ source: Address?,
122            _ display: FungibleTokenMetadataViews.FTDisplay
123        ) {
124            self.source = source
125            self.display = display
126        }
127    }
128
129    /// The struct for the Fungible Token Paths
130    ///
131    access(all) struct StandardTokenPaths {
132        access(all)
133        let vaultPath: StoragePath
134        access(all)
135        let balancePath: PublicPath
136        access(all)
137        let receiverPath: PublicPath
138
139        view init(
140            vaultPath: StoragePath,
141            balancePath: PublicPath,
142            receiverPath: PublicPath,
143        ) {
144            self.vaultPath = vaultPath
145            self.balancePath = balancePath
146            self.receiverPath = receiverPath
147        }
148    }
149
150    /// The struct interface for the Bridged Token View
151    access(all) struct interface IBridgedTokenView {
152        access(all)
153        let evmAddress: String
154    }
155
156    /// The interface for the Token View
157    access(all) struct interface ITokenView {
158        access(all)
159        let tags: [String]
160        access(all)
161        let dataSource: Address?
162
163        access(all)
164        view fun getIdentity(): {TokenIdentity}
165    }
166
167    /// The struct for the Fungible Token List View
168    ///
169    access(all) struct StandardTokenView: ITokenView {
170        access(all)
171        let identity: FTIdentity
172        access(all)
173        let decimals: UInt8
174        access(all)
175        let tags: [String]
176        access(all)
177        let dataSource: Address?
178        access(all)
179        let paths: StandardTokenPaths?
180        access(all)
181        let display: FTDisplayWithSource?
182
183        view init(
184            identity: FTIdentity,
185            decimals: UInt8,
186            tags: [String],
187            dataSource: Address?,
188            paths: StandardTokenPaths?,
189            display: FTDisplayWithSource?,
190        ) {
191            self.identity = identity
192            self.decimals = decimals
193            self.tags = tags
194            self.dataSource = dataSource
195            self.paths = paths
196            self.display = display
197        }
198
199        access(all)
200        view fun getIdentity(): {TokenIdentity} {
201            return self.identity
202        }
203    }
204
205    /// The struct for the Bridged Token View
206    ///
207    access(all) struct BridgedTokenView: ITokenView, IBridgedTokenView {
208        access(all)
209        let identity: FTIdentity
210        access(all)
211        let evmAddress: String
212        access(all)
213        let decimals: UInt8
214        access(all)
215        let tags: [String]
216        access(all)
217        let dataSource: Address?
218        access(all)
219        let paths: StandardTokenPaths?
220        access(all)
221        let display: FTDisplayWithSource?
222
223        view init(
224            identity: FTIdentity,
225            evmAddress: String,
226            decimals: UInt8,
227            tags: [String],
228            dataSource: Address?,
229            paths: StandardTokenPaths?,
230            display: FTDisplayWithSource?,
231        ) {
232            self.identity = identity
233            self.evmAddress = evmAddress
234            self.decimals = decimals
235            self.tags = tags
236            self.dataSource = dataSource
237            self.paths = paths
238            self.display = display
239        }
240
241        access(all)
242        view fun getIdentity(): {TokenIdentity} {
243            return self.identity
244        }
245    }
246
247    /// The enum for the Evaluation
248    ///
249    access(all) enum Evaluation: UInt8 {
250        access(all) case UNVERIFIED
251        access(all) case PENDING
252        access(all) case VERIFIED
253        access(all) case FEATURED
254        access(all) case BLOCKED
255    }
256
257    /// The struct for the Review Comment
258    ///
259    access(all) struct ReviewComment {
260        access(all)
261        let comment: String
262        access(all)
263        let by: Address
264        access(all)
265        let at: UInt64
266
267        view init(_ comment: String, _ by: Address) {
268            self.comment = comment
269            self.by = by
270            self.at = UInt64(getCurrentBlock().timestamp)
271        }
272    }
273
274    /// The struct for the FT Review
275    ///
276    access(all) struct FTReview {
277        access(all)
278        let comments: [ReviewComment]
279        access(all)
280        let tags: [String]
281        access(all)
282        var evalRank: Evaluation
283
284        init(
285            _ rank: Evaluation,
286        ) {
287            self.evalRank = rank
288            self.tags = []
289            self.comments = []
290        }
291
292        /// Get tags
293        ///
294        access(all)
295        view fun getTags(): [String] {
296            return self.tags
297        }
298
299        /// Get getEvaluationRank
300        ///
301        access(all)
302        view fun getEvaluationRank(): Evaluation {
303            return self.evalRank
304        }
305
306        /// Update the evaluation rank
307        ///
308        access(all)
309        fun updateEvaluationRank(
310            _ rank: Evaluation
311        ) {
312            self.evalRank = rank
313        }
314
315        /// Add a new comment to the review
316        ///
317        access(all)
318        fun addComment(_ comment: String, _ by: Address) {
319            self.comments.append(ReviewComment(comment, by))
320        }
321
322        /// Add a new tag to the review
323        ///
324        access(all)
325        fun addTag(_ tag: String): Bool {
326            if !self.tags.contains(tag) {
327                self.tags.append(tag)
328                return true
329            }
330            return false
331        }
332    }
333
334    /// The struct for the Reviewer Info
335    ///
336    access(all) struct ReviewerInfo {
337        access(all)
338        let address: Address
339        access(all)
340        let verified: Bool
341        access(all)
342        let name: String?
343        access(all)
344        let url: String?
345        access(all)
346        let managedTokenAmt: Int
347        access(all)
348        let reviewedTokenAmt: Int
349        access(all)
350        let customziedTokenAmt: Int
351
352        view init(
353            address: Address,
354            verified: Bool,
355            name: String?,
356            url: String?,
357            _ managedTokenAmt: Int,
358            _ reviewedTokenAmt: Int,
359            _ customziedTokenAmt: Int,
360        ) {
361            self.address = address
362            self.verified = verified
363            self.name = name
364            self.url = url
365            self.managedTokenAmt = managedTokenAmt
366            self.reviewedTokenAmt = reviewedTokenAmt
367            self.customziedTokenAmt = customziedTokenAmt
368        }
369    }
370
371    /** Editable FTView */
372
373    /// The enum for the FT Capability Path
374    ///
375    access(all) enum FTCapPath: UInt8 {
376        access(all) case receiver
377        access(all) case metadata
378        access(all) case provider
379    }
380
381    /// The interface for the Editable FT View Data
382    ///
383    access(all) resource interface EditableFTViewDataInterface {
384        /// Identity of the FT
385        access(all)
386        let identity: FTIdentity
387        // ----- FT Vault Data -----
388        /// Get the Storage Path
389        access(all)
390        view fun getStoragePath(): StoragePath
391        /// Get the Receiver Path
392        access(all)
393        view fun getReceiverPath(): PublicPath?
394        /// Get the Metadata Path
395        access(all)
396        view fun getMetadataPath(): PublicPath?
397        /// Get the Provider Path
398        access(all)
399        view fun getProviderPath(): PrivatePath?
400        /// Get the Capability Path
401        access(all)
402        view fun getCapabilityType(_ capPath: FTCapPath): Type?
403        // --- default implementation ---
404        /// Check if the FT View Data is initialized
405        ///
406        access(all)
407        view fun isInitialized(): Bool {
408            return self.getReceiverPath() != nil &&
409                self.getMetadataPath() != nil &&
410                self.getProviderPath() != nil &&
411                self.getCapabilityType(FTCapPath.receiver) != nil &&
412                self.getCapabilityType(FTCapPath.metadata) != nil &&
413                self.getCapabilityType(FTCapPath.provider) != nil
414        }
415        /// Get the FT Vault Data
416        ///
417        access(all)
418        fun getFTVaultData(): FungibleTokenMetadataViews.FTVaultData {
419            pre {
420                self.isInitialized(): "FT View Data is not initialized"
421            }
422            let ftRef = self.identity.borrowFungibleTokenContract()
423            let ftType = self.identity.buildType()
424            return FungibleTokenMetadataViews.FTVaultData(
425                storagePath: self.getStoragePath(),
426                receiverPath: self.getReceiverPath()!,
427                metadataPath: self.getMetadataPath()!,
428                receiverLinkedType: Type<&{FungibleToken.Receiver}>(),
429                metadataLinkedType: Type<&{FungibleToken.Vault}>(),
430                createEmptyVaultFunction: (fun (): @{FungibleToken.Vault} {
431                    return <- ftRef.createEmptyVault(vaultType: ftType)
432                })
433            )
434        }
435    }
436
437    /// The interface for the Editable FT View Display
438    ///
439    access(all) resource interface EditableFTViewDisplayInterface: ViewResolver.Resolver {
440        /// Identity of the FT
441        access(all)
442        let identity: FTIdentity
443        // ----- FT Display -----
444        access(all)
445        view fun getSymbol(): String?
446        access(all)
447        view fun getName(): String?
448        access(all)
449        view fun getDescription(): String?
450        access(all)
451        view fun getExternalURL(): MetadataViews.ExternalURL?
452        access(all)
453        view fun getSocials(): {String: MetadataViews.ExternalURL}
454        access(all)
455        fun getLogos(): MetadataViews.Medias
456        // --- default implementation ---
457        /// Get the FT Display
458        ///
459        access(all)
460        fun getFTDisplay(): FungibleTokenMetadataViews.FTDisplay {
461            return FungibleTokenMetadataViews.FTDisplay(
462                name: self.getName() ?? "Unknown Token",
463                symbol: self.getSymbol() ?? "NONE",
464                description: self.getDescription() ?? "No Description",
465                externalURL: self.getExternalURL() ?? MetadataViews.ExternalURL("https://fixes.world"),
466                logos: self.getLogos(),
467                socials: self.getSocials()
468            )
469        }
470    }
471
472    /// The interface for the FT View Data Editor
473    ///
474    access(all) resource interface FTViewDataEditor: EditableFTViewDataInterface {
475        /// Update the Storage Path
476        access(Editable)
477        fun updateStoragePath(_ storagePath: StoragePath)
478        /// Set the FT Vault Data
479        access(Editable)
480        fun initializeVaultData(
481            receiverPath: PublicPath,
482            metadataPath: PublicPath,
483            receiverType: Type,
484            metadataType: Type,
485        )
486    }
487
488    /// The interface for the FT View Display Editor
489    ///
490    access(all) resource interface FTViewDisplayEditor: EditableFTViewDisplayInterface {
491        /// Set the FT Display
492        access(Editable)
493        fun setFTDisplay(
494            name: String?,
495            symbol: String?,
496            description: String?,
497            externalURL: String?,
498            logo: String?,
499            socials: {String: String}
500        )
501    }
502
503    /// The Resource for the FT Display
504    ///
505    access(all) resource EditableFTDisplay: FTViewDisplayEditor, EditableFTViewDisplayInterface, ViewResolver.Resolver {
506        access(all)
507        let identity: FTIdentity
508        access(contract)
509        let metadata: {String: String}
510
511        init(
512            _ address: Address,
513            _ contractName: String,
514        ) {
515            self.identity = FTIdentity(address, contractName)
516            self.metadata = {}
517        }
518
519        /// Set the FT Display
520        ///
521        access(Editable)
522        fun setFTDisplay(
523            name: String?,
524            symbol: String?,
525            description: String?,
526            externalURL: String?,
527            logo: String?,
528            socials: {String: String}
529        ) {
530            // set name
531            if name != nil {
532                self.metadata["name"] = name!
533            }
534            // set symbol
535            if symbol != nil {
536                self.metadata["symbol"] = symbol!
537            }
538            // set description
539            if description != nil {
540                self.metadata["description"] = description!
541            }
542            // set external URL
543            if externalURL != nil {
544                self.metadata["externalURL"] = externalURL!
545            }
546            // set logo
547            if logo != nil {
548                // the last 3 chars are file type, check the type
549                let fileType = logo!.slice(from: logo!.length - 3, upTo: logo!.length)
550                if fileType == "png" {
551                    self.metadata["logo:png"] = logo!
552                } else if fileType == "svg" {
553                    self.metadata["logo:svg"] = logo!
554                } else if fileType == "jpg" {
555                    self.metadata["logo:jpg"] = logo!
556                } else {
557                    self.metadata["logo"] = logo!
558                }
559            }
560            // set socials
561            for key in socials.keys {
562                self.metadata["social:".concat(key)] = socials[key]!
563            }
564
565            // Emit the event
566            emit FTDisplayUpdated(
567                address: self.identity.address,
568                contractName: self.identity.contractName,
569                name: name,
570                symbol: symbol,
571                description: description,
572                externalURL: externalURL,
573                logo: logo,
574                socials: socials
575            )
576        }
577
578        /** ---- Implement the EditableFTViewDisplayInterface ---- */
579
580        access(all)
581        view fun getSymbol(): String? {
582            return self.metadata["symbol"]
583        }
584
585        access(all)
586        view fun getName(): String? {
587            return self.metadata["name"]
588        }
589
590        access(all)
591        view fun getDescription(): String? {
592            return self.metadata["description"]
593        }
594
595        access(all)
596        view fun getExternalURL(): MetadataViews.ExternalURL? {
597            let url = self.metadata["externalURL"]
598            return url != nil ? MetadataViews.ExternalURL(url!) : nil
599        }
600
601        access(all)
602        fun getLogos(): MetadataViews.Medias {
603            let medias: [MetadataViews.Media] = []
604            if self.metadata["logo:png"] != nil {
605                medias.append(MetadataViews.Media(
606                    file: MetadataViews.HTTPFile(url: self.metadata["logo:png"]!),
607                    mediaType: "image/png" // default is png
608                ))
609            }
610            if self.metadata["logo:svg"] != nil {
611                medias.append(MetadataViews.Media(
612                    file: MetadataViews.HTTPFile(url: self.metadata["logo:svg"]!),
613                    mediaType: "image/svg+xml"
614                ))
615            }
616            if self.metadata["logo:jpg"] != nil {
617                medias.append(MetadataViews.Media(
618                    file: MetadataViews.HTTPFile(url: self.metadata["logo:jpg"]!),
619                    mediaType: "image/jpeg"
620                ))
621            }
622            if self.metadata["logo"] != nil {
623                medias.append(MetadataViews.Media(
624                    file: MetadataViews.HTTPFile(url: self.metadata["logo"]!),
625                    mediaType: "image/*"
626                ))
627            }
628            // add default icon
629            if medias.length == 0 {
630                let ticker = self.getSymbol() ?? self.getName() ?? "NONE"
631                let tickNameSize = 80 + (10 - ticker.length > 0 ? 10 - ticker.length : 0) * 12
632                let svgStr = "data:image/svg+xml;utf8,"
633                    .concat("%3Csvg%20xmlns%3D%5C%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%5C%22%20viewBox%3D%5C%22-256%20-256%20512%20512%5C%22%20width%3D%5C%22512%5C%22%20height%3D%5C%22512%5C%22%3E")
634                    .concat("%3Cdefs%3E%3ClinearGradient%20gradientUnits%3D%5C%22userSpaceOnUse%5C%22%20x1%3D%5C%220%5C%22%20y1%3D%5C%22-240%5C%22%20x2%3D%5C%220%5C%22%20y2%3D%5C%22240%5C%22%20id%3D%5C%22gradient-0%5C%22%20gradientTransform%3D%5C%22matrix(0.908427%2C%20-0.41805%2C%200.320369%2C%200.696163%2C%20-69.267567%2C%20-90.441103)%5C%22%3E%3Cstop%20offset%3D%5C%220%5C%22%20style%3D%5C%22stop-color%3A%20rgb(244%2C%20246%2C%20246)%3B%5C%22%3E%3C%2Fstop%3E%3Cstop%20offset%3D%5C%221%5C%22%20style%3D%5C%22stop-color%3A%20rgb(35%2C%20133%2C%2091)%3B%5C%22%3E%3C%2Fstop%3E%3C%2FlinearGradient%3E%3C%2Fdefs%3E")
635                    .concat("%3Cellipse%20style%3D%5C%22fill%3A%20rgb(149%2C%20225%2C%20192)%3B%20stroke-width%3A%201rem%3B%20paint-order%3A%20fill%3B%20stroke%3A%20url(%23gradient-0)%3B%5C%22%20ry%3D%5C%22240%5C%22%20rx%3D%5C%22240%5C%22%3E%3C%2Fellipse%3E")
636                    .concat("%3Ctext%20style%3D%5C%22dominant-baseline%3A%20middle%3B%20fill%3A%20rgb(80%2C%20213%2C%20155)%3B%20font-family%3A%20system-ui%2C%20sans-serif%3B%20text-anchor%3A%20middle%3B%5C%22%20fill-opacity%3D%5C%220.2%5C%22%20y%3D%5C%22-12%5C%22%20font-size%3D%5C%22420%5C%22%3E%F0%9D%94%89%3C%2Ftext%3E")
637                    .concat("%3Ctext%20style%3D%5C%22dominant-baseline%3A%20middle%3B%20fill%3A%20rgb(244%2C%20246%2C%20246)%3B%20font-family%3A%20system-ui%2C%20sans-serif%3B%20text-anchor%3A%20middle%3B%20font-style%3A%20italic%3B%20font-weight%3A%20700%3B%5C%22%20y%3D%5C%2212%5C%22%20font-size%3D%5C%22").concat(tickNameSize.toString()).concat("%5C%22%3E")
638                    .concat(ticker).concat("%3C%2Ftext%3E%3C%2Fsvg%3E")
639                medias.append(MetadataViews.Media(
640                    file: MetadataViews.HTTPFile(url: svgStr),
641                    mediaType: "image/svg+xml"
642                ))
643            }
644            return MetadataViews.Medias(medias)
645        }
646
647        access(all)
648        view fun getSocials(): {String: MetadataViews.ExternalURL} {
649            let ret: {String: MetadataViews.ExternalURL} = {}
650            let socialKey = "social:"
651            let socialKeyLen = socialKey.length
652            for key in self.metadata.keys {
653                if key.length >= socialKeyLen && key.slice(from: 0, upTo: socialKey.length) == socialKey {
654                    let socialName = key.slice(from: socialKey.length, upTo: key.length)
655                    ret[socialName] = MetadataViews.ExternalURL(self.metadata[key]!)
656                }
657            }
658            return ret
659        }
660
661        /* --- Implement the MetadataViews.Resolver --- */
662
663        access(all)
664        view fun getViews(): [Type] {
665            return [
666                Type<FungibleTokenMetadataViews.FTDisplay>()
667            ]
668        }
669
670        access(all)
671        fun resolveView(_ view: Type): AnyStruct? {
672            switch view {
673                case Type<FungibleTokenMetadataViews.FTDisplay>():
674                    return self.getFTDisplay()
675            }
676            return nil
677        }
678    }
679
680    /// Create the FT View Data
681    ///
682    access(all)
683    fun createEditableFTDisplay(
684        _ address: Address,
685        _ contractName: String,
686    ): @EditableFTDisplay {
687        return <- create EditableFTDisplay(address, contractName)
688    }
689
690    /// The Resource for the FT View
691    ///
692    access(all) resource EditableFTView: FTViewDataEditor, EditableFTViewDataInterface, FTViewDisplayEditor, EditableFTViewDisplayInterface, ViewResolver.Resolver {
693        access(self)
694        let display: @EditableFTDisplay
695        access(all)
696        let identity: FTIdentity
697        access(contract)
698        var storagePath: StoragePath
699        access(contract)
700        let capabilityPaths: {FTCapPath: CapabilityPath}
701        access(contract)
702        let capabilityTypes: {FTCapPath: Type}
703
704        init(
705            _ address: Address,
706            _ contractName: String,
707            _ storagePath: StoragePath,
708        ) {
709            self.identity = FTIdentity(address, contractName)
710            self.display <- create EditableFTDisplay(address, contractName)
711            self.capabilityPaths = {}
712            self.capabilityTypes = {}
713            self.storagePath = storagePath
714        }
715
716        // ---- Writable Functions ----
717
718        /// Update the Storage Path
719        ///
720        access(Editable)
721        fun updateStoragePath(_ storagePath: StoragePath) {
722            self.storagePath = storagePath
723
724            emit FTViewStoragePathUpdated(
725                address: self.identity.address,
726                contractName: self.identity.contractName,
727                storagePath: storagePath
728            )
729        }
730
731        /// Initialize the FT View Data
732        ///
733        access(Editable)
734        fun initializeVaultData(
735            receiverPath: PublicPath,
736            metadataPath: PublicPath,
737            receiverType: Type,
738            metadataType: Type,
739        ) {
740            self.capabilityPaths[FTCapPath.receiver] = receiverPath
741            self.capabilityPaths[FTCapPath.metadata] = metadataPath
742            self.capabilityTypes[FTCapPath.receiver] = receiverType
743            self.capabilityTypes[FTCapPath.metadata] = metadataType
744
745            // Emit the event
746            emit FTVaultDataUpdated(
747                address: self.identity.address,
748                contractName: self.identity.contractName,
749                storagePath: self.storagePath,
750                receiverPath: receiverPath,
751                metadataPath: metadataPath,
752                receiverType: receiverType,
753                metadataType: metadataType
754            )
755        }
756
757        /** ---- Implement the EditableFTViewDataInterface ---- */
758
759        access(all)
760        view fun getStoragePath(): StoragePath {
761            return self.storagePath
762        }
763
764        /// Get the Receiver Path
765        access(all)
766        view fun getReceiverPath(): PublicPath? {
767            return self.capabilityPaths[FTCapPath.receiver] as! PublicPath?
768        }
769
770        /// Get the Metadata Path
771        access(all)
772        view fun getMetadataPath(): PublicPath? {
773            return self.capabilityPaths[FTCapPath.metadata] as! PublicPath?
774        }
775
776        /// Get the Provider Path
777        access(all)
778        view fun getProviderPath(): PrivatePath? {
779            return self.capabilityPaths[FTCapPath.provider] as! PrivatePath?
780        }
781
782        /// Get the Capability Path
783        access(all)
784        view fun getCapabilityType(_ capPath: FTCapPath): Type? {
785            return self.capabilityTypes[capPath]
786        }
787
788        /** ---- Implement the FTViewDataEditor ---- */
789
790        /// Set the FT Display
791        ///
792        access(Editable)
793        fun setFTDisplay(
794            name: String?,
795            symbol: String?,
796            description: String?,
797            externalURL: String?,
798            logo: String?,
799            socials: {String: String}
800        ) {
801            self.display.setFTDisplay(
802                name: name,
803                symbol: symbol,
804                description: description,
805                externalURL: externalURL,
806                logo: logo,
807                socials: socials
808            )
809        }
810
811        /** ---- Implement the FTViewDisplayInterface ---- */
812
813        access(all)
814        view fun getSymbol(): String? {
815            return self.display.getSymbol()
816        }
817
818        access(all)
819        view fun getName(): String? {
820            return self.display.getName()
821        }
822
823        access(all)
824        view fun getDescription(): String? {
825            return self.display.getDescription()
826        }
827
828        access(all)
829        view fun getExternalURL(): MetadataViews.ExternalURL? {
830            return self.display.getExternalURL()
831        }
832
833        access(all)
834        fun getLogos(): MetadataViews.Medias {
835            return self.display.getLogos()
836        }
837
838        access(all)
839        view fun getSocials(): {String: MetadataViews.ExternalURL} {
840            return self.display.getSocials()
841        }
842
843        /* --- Implement the MetadataViews.Resolver --- */
844
845        access(all)
846        view fun getViews(): [Type] {
847            return [
848                Type<MetadataViews.ExternalURL>(),
849                Type<FungibleTokenMetadataViews.FTView>(),
850                Type<FungibleTokenMetadataViews.FTDisplay>(),
851                Type<FungibleTokenMetadataViews.FTVaultData>()
852            ]
853        }
854
855        access(all)
856        fun resolveView(_ view: Type): AnyStruct? {
857            switch view {
858                case Type<MetadataViews.ExternalURL>():
859                    return self.getExternalURL()
860                case Type<FungibleTokenMetadataViews.FTView>():
861                    return FungibleTokenMetadataViews.FTView(
862                        ftDisplay: self.getFTDisplay(),
863                        ftVaultData: self.getFTVaultData()
864                    )
865                case Type<FungibleTokenMetadataViews.FTDisplay>():
866                    return self.getFTDisplay()
867                case Type<FungibleTokenMetadataViews.FTVaultData>():
868                    return self.getFTVaultData()
869            }
870            return nil
871        }
872    }
873
874    /// Create the FT View Data
875    ///
876    access(all)
877    fun createEditableFTView(
878        _ address: Address,
879        _ contractName: String,
880        _ storagePath: StoragePath,
881    ): @EditableFTView {
882        return <- create EditableFTView(address, contractName, storagePath)
883    }
884
885    /// Build the FT Vault Type
886    ///
887    access(all)
888    view fun buildFTVaultType(_ address: Address, _ contractName: String): Type? {
889        let addrStr = address.toString()
890        let addrStrNo0x = addrStr.slice(from: 2, upTo: addrStr.length)
891        return CompositeType("A.".concat(addrStrNo0x).concat(".").concat(contractName).concat(".Vault"))
892    }
893}
894