Smart Contract
FUSD
A.3c5959b568896393.FUSD
1import FungibleToken from 0xf233dcee88fe0abe
2import MetadataViews from 0x1d7e57aa55817448
3import FungibleTokenMetadataViews from 0xf233dcee88fe0abe
4
5access(all) contract FUSD: FungibleToken {
6
7 access(all) entitlement MinterProxyOwner
8
9 // Event that is emitted when new tokens are minted
10 access(all) event TokensMinted(amount: UFix64)
11
12 // The storage path for the admin resource
13 access(all) let AdminStoragePath: StoragePath
14
15 // The storage Path for minters' MinterProxy
16 access(all) let MinterProxyStoragePath: StoragePath
17
18 // The public path for minters' MinterProxy capability
19 access(all) let MinterProxyPublicPath: PublicPath
20
21 // Total supply of fusd in existence
22 access(all) var totalSupply: UFix64
23
24 // -------- ViewResolver Functions for MetadataViews --------
25 access(all) view fun getContractViews(resourceType: Type?): [Type] {
26 return [
27 Type<FungibleTokenMetadataViews.FTView>(),
28 Type<FungibleTokenMetadataViews.FTDisplay>(),
29 Type<FungibleTokenMetadataViews.FTVaultData>(),
30 Type<FungibleTokenMetadataViews.TotalSupply>()
31 ]
32 }
33
34 access(all) fun resolveContractView(resourceType: Type?, viewType: Type): AnyStruct? {
35 switch viewType {
36 case Type<FungibleTokenMetadataViews.FTView>():
37 return FungibleTokenMetadataViews.FTView(
38 ftDisplay: self.resolveContractView(resourceType: nil, viewType: Type<FungibleTokenMetadataViews.FTDisplay>()) as! FungibleTokenMetadataViews.FTDisplay?,
39 ftVaultData: self.resolveContractView(resourceType: nil, viewType: Type<FungibleTokenMetadataViews.FTVaultData>()) as! FungibleTokenMetadataViews.FTVaultData?
40 )
41 case Type<FungibleTokenMetadataViews.FTDisplay>():
42 let media = MetadataViews.Media(
43 file: MetadataViews.HTTPFile(
44 url: ""
45 ),
46 mediaType: ""
47 )
48 let medias = MetadataViews.Medias([media])
49 return FungibleTokenMetadataViews.FTDisplay(
50 name: "Flow USD",
51 symbol: "FUSD",
52 description: "Deprecated version of Flow USD. Developers are advised to not use this contract any more",
53 externalURL: MetadataViews.ExternalURL(""),
54 logos: medias,
55 socials: {}
56 )
57 case Type<FungibleTokenMetadataViews.FTVaultData>():
58 return FungibleTokenMetadataViews.FTVaultData(
59 storagePath: /storage/fusdVault,
60 receiverPath: /public/fusdReceiver,
61 metadataPath: /public/fusdBalance,
62 receiverLinkedType: Type<&FUSD.Vault>(),
63 metadataLinkedType: Type<&FUSD.Vault>(),
64 createEmptyVaultFunction: (fun(): @{FungibleToken.Vault} {
65 return <-FUSD.createEmptyVault(vaultType: Type<@FUSD.Vault>())
66 })
67 )
68 case Type<FungibleTokenMetadataViews.TotalSupply>():
69 return FungibleTokenMetadataViews.TotalSupply(
70 totalSupply: FUSD.totalSupply
71 )
72 }
73 return nil
74 }
75
76 // Vault
77 //
78 access(all) resource Vault: FungibleToken.Vault {
79
80 // holds the balance of a users tokens
81 access(all) var balance: UFix64
82
83 // initialize the balance at resource creation time
84 init(balance: UFix64) {
85 self.balance = balance
86 }
87
88 /// Called when a fungible token is burned via the `Burner.burn()` method
89 access(contract) fun burnCallback() {
90 if self.balance > 0.0 {
91 FUSD.totalSupply = FUSD.totalSupply - self.balance
92 }
93 self.balance = 0.0
94 }
95
96 access(all) view fun getViews(): [Type] {
97 return FUSD.getContractViews(resourceType: nil)
98 }
99
100 access(all) fun resolveView(_ view: Type): AnyStruct? {
101 return FUSD.resolveContractView(resourceType: nil, viewType: view)
102 }
103
104 /// getSupportedVaultTypes optionally returns a list of vault types that this receiver accepts
105 access(all) view fun getSupportedVaultTypes(): {Type: Bool} {
106 let supportedTypes: {Type: Bool} = {}
107 supportedTypes[self.getType()] = true
108 return supportedTypes
109 }
110
111 access(all) view fun isSupportedVaultType(type: Type): Bool {
112 return self.getSupportedVaultTypes()[type] ?? false
113 }
114
115 /// Asks if the amount can be withdrawn from this vault
116 access(all) view fun isAvailableToWithdraw(amount: UFix64): Bool {
117 return amount <= self.balance
118 }
119
120 // withdraw
121 //
122 access(FungibleToken.Withdraw) fun withdraw(amount: UFix64): @{FungibleToken.Vault} {
123 self.balance = self.balance - amount
124 return <-create Vault(balance: amount)
125 }
126
127 // deposit
128 //
129 access(all) fun deposit(from: @{FungibleToken.Vault}) {
130 let vault <- from as! @FUSD.Vault
131 self.balance = self.balance + vault.balance
132 vault.balance = 0.0
133 destroy vault
134 }
135
136 /// createEmptyVault allows any user to create a new Vault that has a zero balance
137 ///
138 access(all) fun createEmptyVault(): @{FungibleToken.Vault} {
139 return <- FUSD.createEmptyVault(vaultType: Type<@FUSD.Vault>())
140 }
141 }
142
143 // createEmptyVault
144 //
145 access(all) fun createEmptyVault(vaultType: Type): @{FungibleToken.Vault} {
146 pre {
147 vaultType == Type<@FUSD.Vault>(): "Unsupported vault type requested"
148 }
149 return <-create Vault(balance: 0.0)
150 }
151
152 // Minter
153 access(all) resource Minter {
154
155 // mintTokens
156 //
157 // Function that mints new tokens, adds them to the total supply,
158 // and returns them to the calling context.
159 //
160 access(all) fun mintTokens(amount: UFix64): @FUSD.Vault {
161 FUSD.totalSupply = FUSD.totalSupply + amount
162 emit TokensMinted(amount: amount)
163 return <-create Vault(balance: amount)
164 }
165
166 }
167
168 access(all) resource interface MinterProxyPublic {
169 access(all) fun setMinterCapability(cap: Capability<&Minter>)
170 }
171
172 // MinterProxy
173 //
174 // Resource object holding a capability that can be used to mint new tokens.
175 // The resource that this capability represents can be deleted by the admin
176 // in order to unilaterally revoke minting capability if needed.
177 access(all) resource MinterProxy: MinterProxyPublic {
178
179 // access(self) so nobody else can copy the capability and use it.
180 access(self) var minterCapability: Capability<&Minter>?
181
182 // Anyone can call this, but only the admin can create Minter capabilities,
183 // so the type system constrains this to being called by the admin.
184 access(all) fun setMinterCapability(cap: Capability<&Minter>) {
185 self.minterCapability = cap
186 }
187
188 access(MinterProxyOwner) fun mintTokens(amount: UFix64): @FUSD.Vault {
189 return <- self.minterCapability!
190 .borrow()!
191 .mintTokens(amount:amount)
192 }
193
194 init() {
195 self.minterCapability = nil
196 }
197 }
198
199 // Administrator
200 // kept for backwards compatibility
201 access(all) resource Administrator {}
202
203 init() {
204 self.AdminStoragePath = /storage/fusdAdmin
205 self.MinterProxyPublicPath = /public/fusdMinterProxy
206 self.MinterProxyStoragePath = /storage/fusdMinterProxy
207
208 self.totalSupply = 1000.0
209
210 let minter <- create Minter()
211 self.account.storage.save(<-minter, to: self.AdminStoragePath)
212
213 let vault <- create Vault(balance: self.totalSupply)
214
215 // Create a new FUSD Vault and put it in storage
216 self.account.storage.save(<-vault, to: /storage/fusdVault)
217
218 // Create a public capability to the Vault that exposes the Vault interfaces
219 let vaultCap = self.account.capabilities.storage.issue<&FUSD.Vault>(
220 /storage/fusdVault
221 )
222 self.account.capabilities.publish(vaultCap, at: /public/fusdBalance)
223
224 // Create a public Capability to the Vault's Receiver functionality
225 let receiverCap = self.account.capabilities.storage.issue<&FUSD.Vault>(
226 /storage/fusdVault
227 )
228 self.account.capabilities.publish(receiverCap, at: /public/fusdReceiver)
229 }
230}