Smart Contract
FlovatarDustToken
A.921ea449dffec68a.FlovatarDustToken
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