Smart Contract

FlovatarDustToken

A.921ea449dffec68a.FlovatarDustToken

Deployed

2w ago
Feb 11, 2026, 06:35:26 PM UTC

Dependents

200 imports
1import FungibleToken from 0xf233dcee88fe0abe
2import Toucans from 0x577a3c409c5dcb5e
3import FungibleTokenMetadataViews from 0xf233dcee88fe0abe
4import MetadataViews from 0x1d7e57aa55817448
5
6access(all)
7contract FlovatarDustToken: FungibleToken{ 
8	
9	/// Total supply of FlovatarDustTokens in existence
10	access(all)
11	var totalSupply: UFix64
12	
13	/// Name of the path
14	access(all)
15	let VaultReceiverPath: PublicPath
16	
17	access(all)
18	let VaultBalancePath: PublicPath
19	
20	access(all)
21	let VaultStoragePath: StoragePath
22	
23	access(all)
24	let AdminStoragePath: StoragePath
25	
26	/// TokensInitialized
27	///
28	/// The event that is emitted when the contract is created
29	access(all)
30	event TokensInitialized(initialSupply: UFix64)
31	
32	/// TokensWithdrawn
33	///
34	/// The event that is emitted when tokens are withdrawn from a Vault
35	access(all)
36	event TokensWithdrawn(amount: UFix64, from: Address?)
37	
38	/// TokensDeposited
39	///
40	/// The event that is emitted when tokens are deposited to a Vault
41	access(all)
42	event TokensDeposited(amount: UFix64, to: Address?)
43	
44	/// TokensMinted
45	///
46	/// The event that is emitted when new tokens are minted
47	access(all)
48	event TokensMinted(amount: UFix64)
49	
50	/// TokensBurned
51	///
52	/// The event that is emitted when tokens are destroyed
53	access(all)
54	event TokensBurned(amount: UFix64)
55	
56	/// MinterCreated
57	///
58	/// The event that is emitted when a new minter resource is created
59	access(all)
60	event MinterCreated(allowedAmount: UFix64)
61	
62	/// BurnerCreated
63	///
64	/// The event that is emitted when a new burner resource is created
65	access(all)
66	event BurnerCreated()
67
68
69
70	access(all) view fun getContractViews(resourceType: Type?): [Type] {
71        return [
72            Type<FungibleTokenMetadataViews.FTView>(),
73            Type<FungibleTokenMetadataViews.FTDisplay>(),
74            Type<FungibleTokenMetadataViews.FTVaultData>(),
75            Type<FungibleTokenMetadataViews.TotalSupply>()
76        ]
77    }
78
79    access(all) fun resolveContractView(resourceType: Type?, viewType: Type): AnyStruct? {
80        switch viewType {
81            case Type<FungibleTokenMetadataViews.FTView>():
82                return FungibleTokenMetadataViews.FTView(
83                    ftDisplay: self.resolveContractView(resourceType: nil, viewType: Type<FungibleTokenMetadataViews.FTDisplay>()) as! FungibleTokenMetadataViews.FTDisplay?,
84                    ftVaultData: self.resolveContractView(resourceType: nil, viewType: Type<FungibleTokenMetadataViews.FTVaultData>()) as! FungibleTokenMetadataViews.FTVaultData?
85                )
86            case Type<FungibleTokenMetadataViews.FTDisplay>():
87                let media = MetadataViews.Media(
88                        file: MetadataViews.HTTPFile(
89                        url: "https://images.flovatar.com/logo.svg"
90                    ),
91                    mediaType: "image/svg+xml"
92                )
93                let medias = MetadataViews.Medias([media])
94                return FungibleTokenMetadataViews.FTDisplay(
95                    name: "Flovatar Dust Token",
96                    symbol: "DUST",
97                    description: "Flovatar is pioneering a new way to unleash community creativity in Web3 by allowing users to be co-creators of their prized NFTs, instead of just being passive collectors.",
98                    externalURL: MetadataViews.ExternalURL("https://flovatar.com"),
99                    logos: medias,
100                    socials: {
101                        "discord": MetadataViews.ExternalURL("https://discord.gg/flovatar"),
102                        "twitter": MetadataViews.ExternalURL("https://x.com/flovatar"),
103                        "instagram": MetadataViews.ExternalURL("https://instagram.com/flovatar_nft"),
104                        "tiktok": MetadataViews.ExternalURL("https://www.tiktok.com/@flovatar")
105                    }
106                )
107            case Type<FungibleTokenMetadataViews.FTVaultData>():
108                return FungibleTokenMetadataViews.FTVaultData(
109                    storagePath: self.VaultStoragePath,
110                    receiverPath: self.VaultReceiverPath,
111                    metadataPath: self.VaultBalancePath,
112                    receiverLinkedType: Type<&FlovatarDustToken.Vault>(),
113                    metadataLinkedType: Type<&FlovatarDustToken.Vault>(),
114                    createEmptyVaultFunction: (fun(): @{FungibleToken.Vault} {
115                        return <-FlovatarDustToken.createEmptyVault(vaultType: Type<@FlovatarDustToken.Vault>())
116                    })
117                )
118            case Type<FungibleTokenMetadataViews.TotalSupply>():
119                return FungibleTokenMetadataViews.TotalSupply(
120                    totalSupply: FlovatarDustToken.totalSupply
121                )
122        }
123        return nil
124    }
125
126
127
128
129	
130	/// Vault
131	///
132	/// Each user stores an instance of only the Vault in their storage
133	/// The functions in the Vault and governed by the pre and post conditions
134	/// in FungibleToken when they are called.
135	/// The checks happen at runtime whenever a function is called.
136	///
137	/// Resources can only be created in the context of the contract that they
138	/// are defined in, so there is no way for a malicious user to create Vaults
139	/// out of thin air. A special Minter resource needs to be defined to mint
140	/// new tokens.
141	///
142	access(all)
143	resource Vault: FungibleToken.Vault { 
144		
145		/// The total balance of this vault
146		access(all)
147		var balance: UFix64
148		
149		// initialize the balance at resource creation time
150		init(balance: UFix64){ 
151			self.balance = balance
152		}
153		
154		/// withdraw
155		///
156		/// Function that takes an amount as an argument
157		/// and withdraws that amount from the Vault.
158		///
159		/// It creates a new temporary Vault that is used to hold
160		/// the money that is being transferred. It returns the newly
161		/// created Vault to the context that called so it can be deposited
162		/// elsewhere.
163		///
164		access(FungibleToken.Withdraw)
165		fun withdraw(amount: UFix64): @{FungibleToken.Vault}{ 
166			self.balance = self.balance - amount
167			emit TokensWithdrawn(amount: amount, from: self.owner?.address)
168			return <-create Vault(balance: amount)
169		}
170		
171		/// deposit
172		///
173		/// Function that takes a Vault object as an argument and adds
174		/// its balance to the balance of the owners Vault.
175		///
176		/// It is allowed to destroy the sent Vault because the Vault
177		/// was a temporary holder of the tokens. The Vault's balance has
178		/// been consumed and therefore can be destroyed.
179		///
180		access(all)
181		fun deposit(from: @{FungibleToken.Vault}){ 
182			let vault <- from as! @FlovatarDustToken.Vault
183			self.balance = self.balance + vault.balance
184			emit TokensDeposited(amount: vault.balance, to: self.owner?.address)
185			vault.balance = 0.0
186			destroy vault
187		}
188		
189		access(all)
190		fun createEmptyVault(): @{FungibleToken.Vault}{ 
191			return <-create Vault(balance: 0.0)
192		}
193
194
195		
196		access(all)
197		view fun isAvailableToWithdraw(amount: UFix64): Bool{ 
198			return self.balance >= amount
199		}
200
201		access(contract) 
202		fun burnCallback() {
203			if self.balance > 0.0 {
204				FlovatarDustToken.totalSupply = FlovatarDustToken.totalSupply - self.balance
205				emit TokensBurned(amount: self.balance)
206			}
207			self.balance = 0.0
208			
209		}
210
211
212		access(all) 
213		view fun getViews(): [Type] {
214            return FlovatarDustToken.getContractViews(resourceType: nil)
215        }
216
217        access(all) 
218		fun resolveView(_ view: Type): AnyStruct? {
219            return FlovatarDustToken.resolveContractView(resourceType: nil, viewType: view)
220        }
221
222        /// getSupportedVaultTypes optionally returns a list of vault types that this receiver accepts
223        access(all) 
224		view fun getSupportedVaultTypes(): {Type: Bool} {
225            let supportedTypes: {Type: Bool} = {}
226            supportedTypes[self.getType()] = true
227            return supportedTypes
228        }
229
230        access(all) 
231		view fun isSupportedVaultType(type: Type): Bool {
232            return self.getSupportedVaultTypes()[type] ?? false
233        }
234
235
236	}
237	
238	/// createEmptyVault
239	///
240	/// Function that creates a new Vault with a balance of zero
241	/// and returns it to the calling context. A user must call this function
242	/// and store the returned Vault in their storage in order to allow their
243	/// account to be able to receive deposits of this token type.
244	///
245	access(all)
246	fun createEmptyVault(vaultType: Type): @{FungibleToken.Vault}{ 
247		return <-create Vault(balance: 0.0)
248	}
249
250
251	access(all)
252	fun createEmptyDustVault(): @FlovatarDustToken.Vault { 
253		return <-create Vault(balance: 0.0)
254	}
255
256	
257	access(all)
258	resource Administrator{ 
259		
260		/// createNewMinter
261		///
262		/// Function that creates and returns a new minter resource
263		///
264		access(all)
265		fun createNewMinter(allowedAmount: UFix64): @Minter{ 
266			emit MinterCreated(allowedAmount: allowedAmount)
267			return <-create Minter(allowedAmount: allowedAmount)
268		}
269		
270		/// createNewBurner
271		///
272		/// Function that creates and returns a new burner resource
273		///
274		access(all)
275		fun createNewBurner(): @Burner{ 
276			emit BurnerCreated()
277			return <-create Burner()
278		}
279	}
280	
281	/// Minter
282	///
283	/// Resource object that token admin accounts can hold to mint new tokens.
284	///
285	access(all)
286	resource Minter: Toucans.Minter{ 
287		
288		/// The amount of tokens that the minter is allowed to mint
289		access(all)
290		var allowedAmount: UFix64
291		
292		/// mintTokens
293		///
294		/// Function that mints new tokens, adds them to the total supply,
295		/// and returns them to the calling context.
296		///
297		access(all)
298		fun mintTokens(amount: UFix64): @FlovatarDustToken.Vault{ 
299			pre{ 
300				amount > 0.0:
301					"Amount minted must be greater than zero"
302				amount <= self.allowedAmount:
303					"Amount minted must be less than the allowed amount"
304			}
305			FlovatarDustToken.totalSupply = FlovatarDustToken.totalSupply + amount
306			self.allowedAmount = self.allowedAmount - amount
307			emit TokensMinted(amount: amount)
308			return <-create Vault(balance: amount)
309		}
310		
311		access(all)
312		fun mint(amount: UFix64): @Vault{ 
313			let vault <- self.mintTokens(amount: amount) as @Vault
314			return <-vault
315		}
316		
317		init(allowedAmount: UFix64){ 
318			self.allowedAmount = allowedAmount
319		}
320	}
321	
322	/// Burner
323	///
324	/// Resource object that token admin accounts can hold to burn tokens.
325	///
326	access(all)
327	resource Burner{ 
328		
329		/// burnTokens
330		///
331		/// Function that destroys a Vault instance, effectively burning the tokens.
332		///
333		/// Note: the burned tokens are automatically subtracted from the
334		/// total supply in the Vault destructor.
335		///
336		access(all)
337		fun burnTokens(from: @{FungibleToken.Vault}){ 
338			let vault <- from as! @FlovatarDustToken.Vault
339			let amount = vault.balance
340			destroy vault
341			emit TokensBurned(amount: amount)
342		}
343	}
344	
345	init(){ 
346		self.totalSupply = 500000000.0
347		self.VaultReceiverPath = /public/FlovatarDustTokenReceiver
348		self.VaultBalancePath = /public/FlovatarDustTokenBalance
349		self.VaultStoragePath = /storage/FlovatarDustTokenVault
350		self.AdminStoragePath = /storage/FlovatarDustTokenAdmin
351		
352		// Create the Vault with the total supply of tokens and save it in storage
353		//
354		let vault <- create Vault(balance: self.totalSupply)
355		self.account.storage.save(<-vault, to: self.VaultStoragePath)
356		
357		// Create a public capability to the stored Vault that only exposes
358		// the `deposit` method through the `Receiver` interface
359		//
360		var capability_1 = self.account.capabilities.storage.issue<&{FungibleToken.Receiver, FungibleToken.Balance}>(self.VaultStoragePath)
361		self.account.capabilities.publish(capability_1, at: self.VaultReceiverPath)
362		
363		// Create a public capability to the stored Vault that only exposes
364		// the `balance` field through the `Balance` interface
365		//
366		var capability_2 = self.account.capabilities.storage.issue<&FlovatarDustToken.Vault>(self.VaultStoragePath)
367		self.account.capabilities.publish(capability_2, at: self.VaultBalancePath)
368		let admin <- create Administrator()
369		self.account.storage.save(<-admin, to: self.AdminStoragePath)
370		
371		// Emit an event that shows that the contract was initialized
372		//
373		emit TokensInitialized(initialSupply: self.totalSupply)
374	}
375}
376