Smart Contract

FUSD

A.3c5959b568896393.FUSD

Deployed

1d ago
Feb 25, 2026, 01:29:17 AM UTC

Dependents

659 imports
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}