Smart Contract

ArtDropToken

A.0e964e9e2b53ed06.ArtDropToken

Valid From

141,257,164

Deployed

3w ago
Feb 07, 2026, 04:07:44 AM UTC

Dependents

0 imports
1import FungibleToken from 0xf233dcee88fe0abe
2import MetadataViews from 0x1d7e57aa55817448
3import FungibleTokenMetadataViews from 0xf233dcee88fe0abe
4
5access(all) contract ArtDropToken: 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 ArtDropTokens 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 AdminStoragePath: 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                        url: "https://assets.website-files.com/5f6294c0c7a8cdd643b1c820/5f6294c0c7a8cda55cb1c936_Flow_Wordmark.svg"
39                    ),
40                    mediaType: "image/svg+xml"
41                )
42                let medias = MetadataViews.Medias([media])
43                return FungibleTokenMetadataViews.FTDisplay(
44                    name: "Example Fungible Token",
45                    symbol: "EFT",
46                    description: "This fungible token is used as an example to help you develop your next FT #onFlow.",
47                    externalURL: MetadataViews.ExternalURL("https://example-ft.onflow.org"),
48                    logos: medias,
49                    socials: {
50                        "twitter": MetadataViews.ExternalURL("https://twitter.com/flow_blockchain")
51                    }
52                )
53            case Type<FungibleTokenMetadataViews.FTVaultData>():
54                return FungibleTokenMetadataViews.FTVaultData(
55                    storagePath: self.VaultStoragePath,
56                    receiverPath: self.ReceiverPublicPath,
57                    metadataPath: self.VaultPublicPath,
58                    receiverLinkedType: Type<&ArtDropToken.Vault>(),
59                    metadataLinkedType: Type<&ArtDropToken.Vault>(),
60                    createEmptyVaultFunction: (fun(): @{FungibleToken.Vault} {
61                        return <-ArtDropToken.createEmptyVault(vaultType: Type<@ArtDropToken.Vault>())
62                    })
63                )
64            case Type<FungibleTokenMetadataViews.TotalSupply>():
65                return FungibleTokenMetadataViews.TotalSupply(
66                    totalSupply: ArtDropToken.totalSupply
67                )
68        }
69        return nil
70    }
71
72    /// Vault
73    ///
74    /// Each user stores an instance of only the Vault in their storage
75    /// The functions in the Vault and governed by the pre and post conditions
76    /// in FungibleToken when they are called.
77    /// The checks happen at runtime whenever a function is called.
78    ///
79    /// Resources can only be created in the context of the contract that they
80    /// are defined in, so there is no way for a malicious user to create Vaults
81    /// out of thin air. A special Minter resource needs to be defined to mint
82    /// new tokens.
83    ///
84    access(all) resource Vault: FungibleToken.Vault {
85
86        /// The total balance of this vault
87        access(all) var balance: UFix64
88
89        // initialize the balance at resource creation time
90        init(balance: UFix64) {
91            self.balance = balance
92        }
93
94        /// Called when a fungible token is burned via the `Burner.burn()` method
95        access(contract) fun burnCallback() {
96            if self.balance > 0.0 {
97                ArtDropToken.totalSupply = ArtDropToken.totalSupply - self.balance
98            }
99            self.balance = 0.0
100        }
101
102        /// In fungible tokens, there are no specific views for specific vaults,
103        /// So we can route calls to view functions to the contract views functions
104        access(all) view fun getViews(): [Type] {
105            return ArtDropToken.getContractViews(resourceType: nil)
106        }
107
108        access(all) fun resolveView(_ view: Type): AnyStruct? {
109            return ArtDropToken.resolveContractView(resourceType: nil, viewType: view)
110        }
111
112        /// getSupportedVaultTypes optionally returns a list of vault types that this receiver accepts
113        access(all) view fun getSupportedVaultTypes(): {Type: Bool} {
114            let supportedTypes: {Type: Bool} = {}
115            supportedTypes[self.getType()] = true
116            return supportedTypes
117        }
118
119        access(all) view fun isSupportedVaultType(type: Type): Bool {
120            return self.getSupportedVaultTypes()[type] ?? false
121        }
122
123        /// Asks if the amount can be withdrawn from this vault
124        access(all) view fun isAvailableToWithdraw(amount: UFix64): Bool {
125            return amount <= self.balance
126        }
127
128        /// withdraw
129        ///
130        /// Function that takes an amount as an argument
131        /// and withdraws that amount from the Vault.
132        ///
133        /// It creates a new temporary Vault that is used to hold
134        /// the tokens that are being transferred. It returns the newly
135        /// created Vault to the context that called so it can be deposited
136        /// elsewhere.
137        ///
138        access(FungibleToken.Withdraw) fun withdraw(amount: UFix64): @ArtDropToken.Vault {
139            self.balance = self.balance - amount
140            return <-create Vault(balance: amount)
141        }
142
143        /// deposit
144        ///
145        /// Function that takes a Vault object as an argument and adds
146        /// its balance to the balance of the owners Vault.
147        ///
148        /// It is allowed to destroy the sent Vault because the Vault
149        /// was a temporary holder of the tokens. The Vault's balance has
150        /// been consumed and therefore can be destroyed.
151        ///
152        access(all) fun deposit(from: @{FungibleToken.Vault}) {
153            let vault <- from as! @ArtDropToken.Vault
154            self.balance = self.balance + vault.balance
155            destroy vault
156        }
157
158        /// createEmptyVault
159        ///
160        /// Function that creates a new Vault with a balance of zero
161        /// and returns it to the calling context. A user must call this function
162        /// and store the returned Vault in their storage in order to allow their
163        /// account to be able to receive deposits of this token type.
164        ///
165        access(all) fun createEmptyVault(): @ArtDropToken.Vault {
166            return <-create Vault(balance: 0.0)
167        }
168    }
169
170    /// Minter
171    ///
172    /// Resource object that token admin accounts can hold to mint new tokens.
173    ///
174    access(all) resource Minter {
175        /// mintTokens
176        ///
177        /// Function that mints new tokens, adds them to the total supply,
178        /// and returns them to the calling context.
179        ///
180        access(all) fun mintTokens(amount: UFix64): @ArtDropToken.Vault {
181            ArtDropToken.totalSupply = ArtDropToken.totalSupply + amount
182            let vault <-create Vault(balance: amount)
183            emit TokensMinted(amount: amount, type: vault.getType().identifier)
184            return <-vault
185        }
186    }
187
188    /// createEmptyVault
189    ///
190    /// Function that creates a new Vault with a balance of zero
191    /// and returns it to the calling context. A user must call this function
192    /// and store the returned Vault in their storage in order to allow their
193    /// account to be able to receive deposits of this token type.
194    ///
195    access(all) fun createEmptyVault(vaultType: Type): @ArtDropToken.Vault {
196        return <- create Vault(balance: 0.0)
197    }
198
199    init() {
200        self.totalSupply = 0.0
201
202        self.VaultStoragePath = /storage/ArtDropTokenVault
203        self.VaultPublicPath = /public/ArtDropTokenVault
204        self.ReceiverPublicPath = /public/ArtDropTokenReceiver
205        self.AdminStoragePath = /storage/ArtDropTokenAdmin 
206
207        let admin <- create Minter()
208
209        // Create the Vault with the total supply of tokens and save it in storage
210        //
211        let vault <- admin.mintTokens(amount: 1000.0)
212
213        self.account.storage.save(<-vault, to: self.VaultStoragePath)
214
215        self.account.storage.save(<-admin, to: self.AdminStoragePath)
216
217        // Create a public capability to the stored Vault that exposes
218        // the `deposit` method and getAcceptedTypes method through the `Receiver` interface
219        // and the `balance` method through the `Balance` interface
220        //
221        let ArtDropTokenCap = self.account.capabilities.storage.issue<&ArtDropToken.Vault>(self.VaultStoragePath)
222        self.account.capabilities.publish(ArtDropTokenCap, at: self.VaultPublicPath)
223        let receiverCap = self.account.capabilities.storage.issue<&ArtDropToken.Vault>(self.VaultStoragePath)
224        self.account.capabilities.publish(receiverCap, at: self.ReceiverPublicPath)
225    }
226}