Smart Contract
FooToken
A.3eebe1cb4a1126b2.FooToken
1import FungibleToken from 0xf233dcee88fe0abe
2import MetadataViews from 0x1d7e57aa55817448
3import FungibleTokenMetadataViews from 0xf233dcee88fe0abe
4
5access(all) contract FooToken: FungibleToken {
6
7 /// The event that is emitted when new tokens are minted
8 access(all) event TokensMinted(amount: UFix64, type: String)
9
10 /// Total supply of FooTokens in existence
11 access(all) var totalSupply: UFix64
12
13 /// Storage and Public Paths
14 access(all) let VaultStoragePath: StoragePath
15 access(all) let VaultPublicPath: PublicPath
16 access(all) let ReceiverPublicPath: PublicPath
17 access(all) let MinterStoragePath: StoragePath
18
19 access(all) view fun getContractViews(resourceType: Type?): [Type] {
20 return [
21 Type<FungibleTokenMetadataViews.FTView>(),
22 Type<FungibleTokenMetadataViews.FTDisplay>(),
23 Type<FungibleTokenMetadataViews.FTVaultData>(),
24 Type<FungibleTokenMetadataViews.TotalSupply>()
25 ]
26 }
27
28 access(all) fun resolveContractView(resourceType: Type?, viewType: Type): AnyStruct? {
29 switch viewType {
30 case Type<FungibleTokenMetadataViews.FTView>():
31 return FungibleTokenMetadataViews.FTView(
32 ftDisplay: self.resolveContractView(resourceType: nil, viewType: Type<FungibleTokenMetadataViews.FTDisplay>()) as! FungibleTokenMetadataViews.FTDisplay?,
33 ftVaultData: self.resolveContractView(resourceType: nil, viewType: Type<FungibleTokenMetadataViews.FTVaultData>()) as! FungibleTokenMetadataViews.FTVaultData?
34 )
35 case Type<FungibleTokenMetadataViews.FTDisplay>():
36 let media = MetadataViews.Media(
37 file: MetadataViews.HTTPFile(
38 // Change this to your own SVG image
39 url: "https://assets.website-files.com/5f6294c0c7a8cdd643b1c820/5f6294c0c7a8cda55cb1c936_Flow_Wordmark.svg"
40 ),
41 mediaType: "image/svg+xml"
42 )
43 let medias = MetadataViews.Medias([media])
44 return FungibleTokenMetadataViews.FTDisplay(
45 // Change these to represent your own token
46 name: "Example Foo Token",
47 symbol: "EFT",
48 description: "This fungible token is used as an example to help you develop your next FT #onFlow.",
49 externalURL: MetadataViews.ExternalURL("https://developers.flow.com/build/guides/fungible-token"),
50 logos: medias,
51 socials: {
52 "twitter": MetadataViews.ExternalURL("https://twitter.com/flow_blockchain")
53 }
54 )
55 case Type<FungibleTokenMetadataViews.FTVaultData>():
56 return FungibleTokenMetadataViews.FTVaultData(
57 storagePath: self.VaultStoragePath,
58 receiverPath: self.VaultPublicPath,
59 metadataPath: self.VaultPublicPath,
60 receiverLinkedType: Type<&FooToken.Vault>(),
61 metadataLinkedType: Type<&FooToken.Vault>(),
62 createEmptyVaultFunction: (fun(): @{FungibleToken.Vault} {
63 return <-FooToken.createEmptyVault(vaultType: Type<@FooToken.Vault>())
64 })
65 )
66 case Type<FungibleTokenMetadataViews.TotalSupply>():
67 return FungibleTokenMetadataViews.TotalSupply(
68 totalSupply: FooToken.totalSupply
69 )
70 }
71 return nil
72 }
73
74 access(all) resource Vault: FungibleToken.Vault {
75
76 /// The total balance of this vault
77 access(all) var balance: UFix64
78
79 // initialize the balance at resource creation time
80 init(balance: UFix64) {
81 self.balance = balance
82 }
83
84 /// Called when a fungible token is burned via the `Burner.burn()` method
85 access(contract) fun burnCallback() {
86 if self.balance > 0.0 {
87 FooToken.totalSupply = FooToken.totalSupply - self.balance
88 }
89 self.balance = 0.0
90 }
91
92 access(all) view fun getViews(): [Type] {
93 return FooToken.getContractViews(resourceType: nil)
94 }
95
96 access(all) fun resolveView(_ view: Type): AnyStruct? {
97 return FooToken.resolveContractView(resourceType: nil, viewType: view)
98 }
99
100 access(all) view fun getSupportedVaultTypes(): {Type: Bool} {
101 let supportedTypes: {Type: Bool} = {}
102 supportedTypes[self.getType()] = true
103 return supportedTypes
104 }
105
106 access(all) view fun isSupportedVaultType(type: Type): Bool {
107 return self.getSupportedVaultTypes()[type] ?? false
108 }
109
110 access(all) view fun isAvailableToWithdraw(amount: UFix64): Bool {
111 return amount <= self.balance
112 }
113
114 access(FungibleToken.Withdraw) fun withdraw(amount: UFix64): @FooToken.Vault {
115 self.balance = self.balance - amount
116 return <-create Vault(balance: amount)
117 }
118
119 access(all) fun deposit(from: @{FungibleToken.Vault}) {
120 let vault <- from as! @FooToken.Vault
121 self.balance = self.balance + vault.balance
122 vault.balance = 0.0
123 destroy vault
124 }
125
126 access(all) fun createEmptyVault(): @FooToken.Vault {
127 return <-create Vault(balance: 0.0)
128 }
129 }
130
131 access(all) resource Minter {
132 /// mintTokens
133 ///
134 /// Function that mints new tokens, adds them to the total supply,
135 /// and returns them to the calling context.
136 ///
137 access(all) fun mintTokens(amount: UFix64): @FooToken.Vault {
138 FooToken.totalSupply = FooToken.totalSupply + amount
139 let vault <-create Vault(balance: amount)
140 emit TokensMinted(amount: amount, type: vault.getType().identifier)
141 return <-vault
142 }
143 }
144
145 access(all) fun createEmptyVault(vaultType: Type): @FooToken.Vault {
146 return <- create Vault(balance: 0.0)
147 }
148
149 init() {
150 self.totalSupply = 1000.0
151
152 self.VaultStoragePath = /storage/fooTokenVault
153 self.VaultPublicPath = /public/fooTokenVault
154 self.ReceiverPublicPath = /public/fooTokenReceiver
155 self.MinterStoragePath = /storage/fooTokenMinter
156
157 // Create the Vault with the total supply of tokens and save it in storage
158 //
159 let vault <- create Vault(balance: self.totalSupply)
160 emit TokensMinted(amount: vault.balance, type: vault.getType().identifier)
161 self.account.storage.save(<-vault, to: self.VaultStoragePath)
162
163 // Create a public capability to the stored Vault that exposes
164 // the `deposit` method and getAcceptedTypes method through the `Receiver` interface
165 // and the `balance` method through the `Balance` interface
166 //
167 let fooTokenCap = self.account.capabilities.storage.issue<&FooToken.Vault>(self.VaultStoragePath)
168 self.account.capabilities.publish(fooTokenCap, at: self.VaultPublicPath)
169
170 let minter <- create Minter()
171 self.account.storage.save(<-minter, to: self.MinterStoragePath)
172 }
173}