Smart Contract

MOET

A.6b00ff876c299c61.MOET

Valid From

142,666,865

Deployed

1w ago
Feb 18, 2026, 10:18:41 PM UTC

Dependents

12 imports
1import FungibleToken from 0xf233dcee88fe0abe
2import MetadataViews from 0x1d7e57aa55817448
3import FungibleTokenMetadataViews from 0xf233dcee88fe0abe
4
5access(all) contract MOET : FungibleToken {
6
7    /// Total supply of MOET in existence
8    access(all) var totalSupply: UFix64
9
10    /// Storage and Public Paths
11    access(all) let VaultStoragePath: StoragePath
12    access(all) let VaultPublicPath: PublicPath
13    access(all) let ReceiverPublicPath: PublicPath
14    access(all) let AdminStoragePath: StoragePath
15
16    /// The event that is emitted when new tokens are minted
17    access(all) event Minted(type: String, amount: UFix64, toUUID: UInt64, minterUUID: UInt64)
18    /// Emitted whenever a new Minter is created
19    access(all) event MinterCreated(uuid: UInt64)
20
21    /// createEmptyVault
22    ///
23    /// Function that creates a new Vault with a balance of zero
24    /// and returns it to the calling context. A user must call this function
25    /// and store the returned Vault in their storage in order to allow their
26    /// account to be able to receive deposits of this token type.
27    ///
28    access(all) fun createEmptyVault(vaultType: Type): @MOET.Vault {
29        return <- create Vault(balance: 0.0)
30    }
31
32    access(all) view fun getContractViews(resourceType: Type?): [Type] {
33        return [
34            Type<FungibleTokenMetadataViews.FTView>(),
35            Type<FungibleTokenMetadataViews.FTDisplay>(),
36            Type<FungibleTokenMetadataViews.FTVaultData>(),
37            Type<FungibleTokenMetadataViews.TotalSupply>()
38        ]
39    }
40
41    access(all) fun resolveContractView(resourceType: Type?, viewType: Type): AnyStruct? {
42        switch viewType {
43            case Type<FungibleTokenMetadataViews.FTView>():
44                return FungibleTokenMetadataViews.FTView(
45                    ftDisplay: self.resolveContractView(resourceType: nil, viewType: Type<FungibleTokenMetadataViews.FTDisplay>()) as! FungibleTokenMetadataViews.FTDisplay?,
46                    ftVaultData: self.resolveContractView(resourceType: nil, viewType: Type<FungibleTokenMetadataViews.FTVaultData>()) as! FungibleTokenMetadataViews.FTVaultData?
47                )
48            case Type<FungibleTokenMetadataViews.FTDisplay>():
49                let media = MetadataViews.Media(
50                        file: MetadataViews.HTTPFile(
51                        url: "https://assets.website-files.com/5f6294c0c7a8cdd643b1c820/5f6294c0c7a8cda55cb1c936_Flow_Wordmark.svg"
52                    ),
53                    mediaType: "image/svg+xml"
54                )
55                let medias = MetadataViews.Medias([media])
56                return FungibleTokenMetadataViews.FTDisplay(
57                    name: "FlowALP USD",
58                    symbol: "MOET",
59                    description: "A Mean Of Exchange Token / FlowALP stablecoin",
60                    externalURL: MetadataViews.ExternalURL("https://flow.com"),
61                    logos: medias,
62                    socials: {
63                        "twitter": MetadataViews.ExternalURL("https://twitter.com/flow_blockchain")
64                    }
65                )
66            case Type<FungibleTokenMetadataViews.FTVaultData>():
67                return FungibleTokenMetadataViews.FTVaultData(
68                    storagePath: self.VaultStoragePath,
69                    receiverPath: self.ReceiverPublicPath,
70                    metadataPath: self.VaultPublicPath,
71                    receiverLinkedType: Type<&MOET.Vault>(),
72                    metadataLinkedType: Type<&MOET.Vault>(),
73                    createEmptyVaultFunction: (fun(): @{FungibleToken.Vault} {
74                        return <-MOET.createEmptyVault(vaultType: Type<@MOET.Vault>())
75                    })
76                )
77            case Type<FungibleTokenMetadataViews.TotalSupply>():
78                return FungibleTokenMetadataViews.TotalSupply(
79                    totalSupply: MOET.totalSupply
80                )
81        }
82        return nil
83    }
84
85    /* --- CONSTRUCTS --- */
86
87    /// Vault
88    ///
89    /// Each user stores an instance of only the Vault in their storage
90    /// The functions in the Vault and governed by the pre and post conditions
91    /// in FungibleToken when they are called.
92    /// The checks happen at runtime whenever a function is called.
93    ///
94    /// Resources can only be created in the context of the contract that they
95    /// are defined in, so there is no way for a malicious user to create Vaults
96    /// out of thin air. A special Minter resource needs to be defined to mint
97    /// new tokens.
98    ///
99    access(all) resource Vault: FungibleToken.Vault {
100
101        /// The total balance of this vault
102        access(all) var balance: UFix64
103
104        /// Identifies the destruction of a Vault even when destroyed outside of Buner.burn() scope
105        access(all) event ResourceDestroyed(uuid: UInt64 = self.uuid, balance: UFix64 = self.balance)
106
107        init(balance: UFix64) {
108            self.balance = balance
109        }
110
111        /// Called when a fungible token is burned via the `Burner.burn()` method
112        access(contract) fun burnCallback() {
113            if self.balance > 0.0 {
114                MOET.totalSupply = MOET.totalSupply - self.balance
115            }
116            self.balance = 0.0
117        }
118
119        access(all) view fun getViews(): [Type] {
120            return MOET.getContractViews(resourceType: nil)
121        }
122
123        access(all) fun resolveView(_ view: Type): AnyStruct? {
124            return MOET.resolveContractView(resourceType: nil, viewType: view)
125        }
126
127        access(all) view fun getSupportedVaultTypes(): {Type: Bool} {
128            let supportedTypes: {Type: Bool} = {}
129            supportedTypes[self.getType()] = true
130            return supportedTypes
131        }
132
133        access(all) view fun isSupportedVaultType(type: Type): Bool {
134            return self.getSupportedVaultTypes()[type] ?? false
135        }
136
137        access(all) view fun isAvailableToWithdraw(amount: UFix64): Bool {
138            return amount <= self.balance
139        }
140
141        access(FungibleToken.Withdraw) fun withdraw(amount: UFix64): @MOET.Vault {
142            self.balance = self.balance - amount
143            return <-create Vault(balance: amount)
144        }
145
146        access(all) fun deposit(from: @{FungibleToken.Vault}) {
147            let vault <- from as! @MOET.Vault
148            let amount = vault.balance
149            vault.balance = 0.0
150            destroy vault
151
152            self.balance = self.balance + amount
153        }
154
155        access(all) fun createEmptyVault(): @MOET.Vault {
156            return <-create Vault(balance: 0.0)
157        }
158    }
159
160    /// Minter
161    ///
162    /// Resource object that token admin accounts can hold to mint new tokens.
163    ///
164    access(all) resource Minter {
165        /// Identifies when a Minter is destroyed, coupling with MinterCreated event to trace Minter UUIDs
166        access(all) event ResourceDestroyed(uuid: UInt64 = self.uuid)
167
168        init() {
169            emit MinterCreated(uuid: self.uuid)
170        }
171
172        /// mintTokens
173        ///
174        /// Function that mints new tokens, adds them to the total supply,
175        /// and returns them to the calling context.
176        ///
177        access(all) fun mintTokens(amount: UFix64): @MOET.Vault {
178            MOET.totalSupply = MOET.totalSupply + amount
179            let vault <-create Vault(balance: amount)
180            emit Minted(type: vault.getType().identifier, amount: amount, toUUID: vault.uuid, minterUUID: self.uuid)
181            return <-vault
182        }
183    }
184
185    init(initialMint: UFix64) {
186        
187        self.totalSupply = 0.0
188        
189        let address = self.account.address
190        self.VaultStoragePath = StoragePath(identifier: "moetTokenVault_\(address)")!
191        self.VaultPublicPath = PublicPath(identifier: "moetTokenVault_\(address)")!
192        self.ReceiverPublicPath = PublicPath(identifier: "moetTokenReceiver_\(address)")!
193        self.AdminStoragePath = StoragePath(identifier: "moetTokenAdmin_\(address)")!
194
195
196        // Create a public capability to the stored Vault that exposes
197        // the `deposit` method and getAcceptedTypes method through the `Receiver` interface
198        // and the `balance` method through the `Balance` interface
199        //
200        self.account.storage.save(<-create Vault(balance: self.totalSupply), to: self.VaultStoragePath)
201        let vaultCap = self.account.capabilities.storage.issue<&MOET.Vault>(self.VaultStoragePath)
202        self.account.capabilities.publish(vaultCap, at: self.VaultPublicPath)
203        let receiverCap = self.account.capabilities.storage.issue<&MOET.Vault>(self.VaultStoragePath)
204        self.account.capabilities.publish(receiverCap, at: self.ReceiverPublicPath)
205
206        // Create a Minter & mint the initial supply of tokens to the contract account's Vault
207        let admin <- create Minter()
208
209        self.account.capabilities.borrow<&Vault>(self.ReceiverPublicPath)!.deposit(
210            from: <- admin.mintTokens(amount: initialMint)
211        )
212
213        self.account.storage.save(<-admin, to: self.AdminStoragePath)
214    }
215}
216