Smart Contract

FungibleTokenMetadataViews

A.f233dcee88fe0abe.FungibleTokenMetadataViews

Deployed

1d ago
Feb 25, 2026, 01:40:38 PM UTC

Dependents

9880 imports
1import FungibleToken from 0xf233dcee88fe0abe
2import MetadataViews from 0x1d7e57aa55817448
3import ViewResolver from 0x1d7e57aa55817448
4
5/// This contract implements the metadata standard proposed
6/// in FLIP-1087.
7/// 
8/// Ref: https://github.com/onflow/flips/blob/main/application/20220811-fungible-tokens-metadata.md
9/// 
10/// Structs and resources can implement one or more
11/// metadata types, called views. Each view type represents
12/// a different kind of metadata.
13///
14access(all) contract FungibleTokenMetadataViews {
15
16    /// FTView wraps FTDisplay and FTVaultData, and is used to give a complete 
17    /// picture of a Fungible Token. Most Fungible Token contracts should 
18    /// implement this view.
19    ///
20    access(all) struct FTView {
21        access(all) let ftDisplay: FTDisplay?     
22        access(all) let ftVaultData: FTVaultData?
23        view init(
24            ftDisplay: FTDisplay?,
25            ftVaultData: FTVaultData?
26        ) {
27            self.ftDisplay = ftDisplay
28            self.ftVaultData = ftVaultData
29        }
30    }
31
32    /// Helper to get a FT view.
33    ///
34    /// @param viewResolver: A reference to the resolver resource
35    /// @return A FTView struct
36    ///
37    access(all) fun getFTView(viewResolver: &{ViewResolver.Resolver}): FTView {
38        let maybeFTView = viewResolver.resolveView(Type<FTView>())
39        if let ftView = maybeFTView {
40            return ftView as! FTView
41        }
42        return FTView(
43            ftDisplay: self.getFTDisplay(viewResolver),
44            ftVaultData: self.getFTVaultData(viewResolver)
45        )
46    }
47
48    /// View to expose the information needed to showcase this FT. 
49    /// This can be used by applications to give an overview and 
50    /// graphics of the FT.
51    ///
52    access(all) struct FTDisplay {
53        /// The display name for this token.
54        ///
55        /// Example: "Flow"
56        ///
57        access(all) let name: String
58
59        /// The abbreviated symbol for this token.
60        ///
61        /// Example: "FLOW"
62        access(all) let symbol: String
63
64        /// A description the provides an overview of this token.
65        ///
66        /// Example: "The FLOW token is the native currency of the Flow network."
67        access(all) let description: String
68
69        /// External link to a URL to view more information about the fungible token.
70        access(all) let externalURL: MetadataViews.ExternalURL
71
72        /// One or more versions of the fungible token logo.
73        access(all) let logos: MetadataViews.Medias
74
75        /// Social links to reach the fungible token's social homepages.
76        /// Possible keys may be "instagram", "twitter", "discord", etc.
77        access(all) let socials: {String: MetadataViews.ExternalURL}
78
79        view init(
80            name: String,
81            symbol: String,
82            description: String,
83            externalURL: MetadataViews.ExternalURL,
84            logos: MetadataViews.Medias,
85            socials: {String: MetadataViews.ExternalURL}
86        ) {
87            self.name = name
88            self.symbol = symbol
89            self.description = description
90            self.externalURL = externalURL
91            self.logos = logos
92            self.socials = socials
93        }
94    }
95
96    /// Helper to get FTDisplay in a way that will return a typed optional.
97    /// 
98    /// @param viewResolver: A reference to the resolver resource
99    /// @return An optional FTDisplay struct
100    ///
101    access(all) fun getFTDisplay(_ viewResolver: &{ViewResolver.Resolver}): FTDisplay? {
102        if let maybeDisplayView = viewResolver.resolveView(Type<FTDisplay>()) {
103            if let displayView = maybeDisplayView as? FTDisplay {
104                return displayView
105            }
106        }
107        return nil
108    }
109
110    /// View to expose the information needed store and interact with a FT vault.
111    /// This can be used by applications to setup a FT vault with proper 
112    /// storage and public capabilities.
113    ///
114    access(all) struct FTVaultData {
115        /// Path in storage where this FT vault is recommended to be stored.
116        access(all) let storagePath: StoragePath
117
118        /// Public path which must be linked to expose the public receiver capability.
119        access(all) let receiverPath: PublicPath
120
121        /// Public path which must be linked to expose the balance and resolver public capabilities.
122        access(all) let metadataPath: PublicPath
123
124        /// Type that should be linked at the `receiverPath`. This is a restricted type requiring 
125        /// the `FungibleToken.Receiver` interface.
126        access(all) let receiverLinkedType: Type
127
128        /// Type that should be linked at the `receiverPath`. This is a restricted type requiring 
129        /// the `ViewResolver.Resolver` interfaces.
130        access(all) let metadataLinkedType: Type
131
132        /// Function that allows creation of an empty FT vault that is intended
133        /// to store the funds.
134        access(all) let createEmptyVault: fun(): @{FungibleToken.Vault}
135
136        view init(
137            storagePath: StoragePath,
138            receiverPath: PublicPath,
139            metadataPath: PublicPath,
140            receiverLinkedType: Type,
141            metadataLinkedType: Type,
142            createEmptyVaultFunction: fun(): @{FungibleToken.Vault}
143        ) {
144            pre {
145                receiverLinkedType.isSubtype(of: Type<&{FungibleToken.Receiver}>()):
146                    "Receiver public type <".concat(receiverLinkedType.identifier)
147                    .concat("> must be a subtype of <").concat(Type<&{FungibleToken.Receiver}>().identifier)
148                    .concat(">.")
149                metadataLinkedType.isSubtype(of: Type<&{FungibleToken.Vault}>()):
150                    "Metadata linked type <".concat(metadataLinkedType.identifier)
151                    .concat("> must be a subtype of <").concat(Type<&{FungibleToken.Vault}>().identifier)
152                    .concat(">.")
153            }
154            self.storagePath = storagePath
155            self.receiverPath = receiverPath
156            self.metadataPath = metadataPath
157            self.receiverLinkedType = receiverLinkedType
158            self.metadataLinkedType = metadataLinkedType
159            self.createEmptyVault = createEmptyVaultFunction
160        }
161    }
162
163    /// Helper to get FTVaultData in a way that will return a typed Optional.
164    ///
165    /// @param viewResolver: A reference to the resolver resource
166    /// @return A optional FTVaultData struct
167    ///
168    access(all) fun getFTVaultData(_ viewResolver: &{ViewResolver.Resolver}): FTVaultData? {
169        if let view = viewResolver.resolveView(Type<FTVaultData>()) {
170            if let v = view as? FTVaultData {
171                return v
172            }
173        }
174        return nil
175    }
176
177    /// View to expose the total supply of the Vault's token
178    access(all) struct TotalSupply {
179        access(all) let supply: UFix64
180
181        view init(totalSupply: UFix64) {
182            self.supply = totalSupply
183        }
184    }
185}
186