Smart Contract

KARATZ1XR82W

A.215f3ac76cb49656.KARATZ1XR82W

Valid From

140,103,113

Deployed

1w ago
Feb 16, 2026, 03:30:59 PM UTC

Dependents

0 imports
1import MetadataViews from 0x1d7e57aa55817448
2import FungibleToken from 0xf233dcee88fe0abe
3import FungibleTokenMetadataViews from 0xf233dcee88fe0abe
4
5access(all) contract KARATZ1XR82W: FungibleToken {
6    // TokensInitialized
7    //
8    // The event that is emitted when the contract is created
9    access(all) event TokensInitialized(initialSupply: UFix64)
10
11    // TokensWithdrawn
12    //
13    // The event that is emitted when tokens are withdrawn from a Vault
14    access(all) event TokensWithdrawn(amount: UFix64, from: Address?)
15
16    // TokensDeposited
17    //
18    // The event that is emitted when tokens are deposited to a Vault
19    access(all) event TokensDeposited(amount: UFix64, to: Address?)
20
21    // TokensBurned
22    //
23    // The event that is emitted when tokens are destroyed
24    access(all) event TokensBurned(amount: UFix64, burner: Address, metadata: {String: String}?)
25
26    /// The event that is emitted when new tokens are minted
27    access(all) event TokensMinted(amount: UFix64, type: String, metadata: {String: String}?)
28
29    /// Total supply of KARATZ1XR82W tokens in existence
30    access(all) var totalSupply: UFix64
31
32    /// Maximum supply cap that can be updated
33    access(all) var maxSupply: UFix64
34
35    /// Initial token supply (S0)
36    access(all) var initialSupply: UFix64
37
38    /// Initial price (P0)
39    access(all) var initialPrice: UFix64
40
41    /// Reserve ratio (R) used for Bancor pricing
42    /// Typical values: 0.1 (10%) - more volatile, 0.5 (50%) - balanced, 0.9 (90%) - stable
43    access(all) var reserveRatio: UFix64
44
45    /// Storage and Public Paths
46    access(all) let VaultStoragePath: StoragePath
47    access(all) let BalancePublicPath: PublicPath
48    access(all) let ReceiverPublicPath: PublicPath
49    access(all) let AdminStoragePath: StoragePath
50
51    access(all) view fun getContractViews(resourceType: Type?): [Type] {
52        return [
53            Type<FungibleTokenMetadataViews.FTView>(),
54            Type<FungibleTokenMetadataViews.FTDisplay>(),
55            Type<FungibleTokenMetadataViews.FTVaultData>(),
56            Type<FungibleTokenMetadataViews.TotalSupply>()
57        ]
58    }
59
60    access(all) fun resolveContractView(resourceType: Type?, viewType: Type): AnyStruct? {
61        switch viewType {
62            case Type<FungibleTokenMetadataViews.FTView>():
63                return FungibleTokenMetadataViews.FTView(
64                    ftDisplay: self.resolveContractView(resourceType: nil, viewType: Type<FungibleTokenMetadataViews.FTDisplay>()) as! FungibleTokenMetadataViews.FTDisplay?,
65                    ftVaultData: self.resolveContractView(resourceType: nil, viewType: Type<FungibleTokenMetadataViews.FTVaultData>()) as! FungibleTokenMetadataViews.FTVaultData?
66                )
67            case Type<FungibleTokenMetadataViews.FTDisplay>():
68                let media = MetadataViews.Media(
69                    file: MetadataViews.HTTPFile(
70                        url: "https://apps.24karat.io/tokens/KARATZ1XR82W/thumbnail.png"
71                    ),
72                    mediaType: "image/png"
73                )
74                return FungibleTokenMetadataViews.FTDisplay(
75                    name: "GKT",
76                    symbol: "KARATZ1XR82W",
77                    description: "GKT",
78                    externalURL: MetadataViews.ExternalURL("https://24karat.io"),
79                    logos: MetadataViews.Medias([media]),
80                    socials: {}
81                )
82            case Type<FungibleTokenMetadataViews.FTVaultData>():
83                return FungibleTokenMetadataViews.FTVaultData(
84                    storagePath: self.VaultStoragePath,
85                    receiverPath: self.ReceiverPublicPath,
86                    metadataPath: self.BalancePublicPath,
87                    receiverLinkedType: Type<&KARATZ1XR82W.Vault>(),
88                    metadataLinkedType: Type<&KARATZ1XR82W.Vault>(),
89                    createEmptyVaultFunction: (fun(): @{FungibleToken.Vault} {
90                        return <-KARATZ1XR82W.createEmptyVault(vaultType: Type<@KARATZ1XR82W.Vault>())
91                    })
92                )
93            case Type<FungibleTokenMetadataViews.TotalSupply>():
94                return FungibleTokenMetadataViews.TotalSupply(
95                    totalSupply: KARATZ1XR82W.totalSupply
96                )
97        }
98        return nil
99    }
100
101    /// Vault
102    ///
103    /// Each user stores an instance of only the Vault in their storage
104    /// The functions in the Vault and governed by the pre and post conditions
105    /// in FungibleToken when they are called.
106    /// The checks happen at runtime whenever a function is called.
107    ///
108    /// Resources can only be created in the context of the contract that they
109    /// are defined in, so there is no way for a malicious user to create Vaults
110    /// out of thin air. A special Minter resource needs to be defined to mint
111    /// new tokens.
112    ///
113    access(all) resource Vault: FungibleToken.Vault {
114
115        /// The total balance of this vault
116        access(all) var balance: UFix64
117
118        // initialize the balance at resource creation time
119        init(balance: UFix64) {
120            self.balance = balance
121        }
122
123        /// Called when a fungible token is burned via the `Burner.burn()` method
124        access(contract) fun burnCallback() {
125            if self.balance > 0.0 {
126                KARATZ1XR82W.totalSupply = KARATZ1XR82W.totalSupply - self.balance
127            }
128            self.balance = 0.0
129        }
130
131        access(all) view fun getViews(): [Type] {
132            return KARATZ1XR82W.getContractViews(resourceType: nil)
133        }
134
135        access(all) fun resolveView(_ view: Type): AnyStruct? {
136            return KARATZ1XR82W.resolveContractView(resourceType: nil, viewType: view)
137        }
138
139        /// getSupportedVaultTypes optionally returns a list of vault types that this receiver accepts
140        access(all) view fun getSupportedVaultTypes(): {Type: Bool} {
141            let supportedTypes: {Type: Bool} = {}
142            supportedTypes[self.getType()] = true
143            return supportedTypes
144        }
145
146        access(all) view fun isSupportedVaultType(type: Type): Bool {
147            return self.getSupportedVaultTypes()[type] ?? false
148        }
149
150        /// Asks if the amount can be withdrawn from this vault
151        access(all) view fun isAvailableToWithdraw(amount: UFix64): Bool {
152            return amount <= self.balance
153        }
154
155        /// withdraw
156        ///
157        /// Function that takes an amount as an argument
158        /// and withdraws that amount from the Vault.
159        ///
160        /// It creates a new temporary Vault that is used to hold
161        /// the tokens that are being transferred. It returns the newly
162        /// created Vault to the context that called so it can be deposited
163        /// elsewhere.
164        ///
165        access(FungibleToken.Withdraw) fun withdraw(amount: UFix64): @KARATZ1XR82W.Vault {
166            self.balance = self.balance - amount
167            return <-create Vault(balance: amount)
168        }
169
170        /// deposit
171        ///
172        /// Function that takes a Vault object as an argument and adds
173        /// its balance to the balance of the owners Vault.
174        ///
175        /// It is allowed to destroy the sent Vault because the Vault
176        /// was a temporary holder of the tokens. The Vault's balance has
177        /// been consumed and therefore can be destroyed.
178        ///
179        access(all) fun deposit(from: @{FungibleToken.Vault}) {
180            let vault <- from as! @KARATZ1XR82W.Vault
181            self.balance = self.balance + vault.balance
182            vault.balance = 0.0
183            destroy vault
184        }
185
186        /// createEmptyVault
187        ///
188        /// Function that creates a new Vault with a balance of zero
189        /// and returns it to the calling context. A user must call this function
190        /// and store the returned Vault in their storage in order to allow their
191        /// account to be able to receive deposits of this token type.
192        ///
193        access(all) fun createEmptyVault(): @KARATZ1XR82W.Vault {
194            return <-create Vault(balance: 0.0)
195        }
196    }
197
198    /// createEmptyVault
199    ///
200    /// Function that creates a new Vault with a balance of zero
201    /// and returns it to the calling context. A user must call this function
202    /// and store the returned Vault in their storage in order to allow their
203    /// account to be able to receive deposits of this token type.
204    ///
205    access(all) fun createEmptyVault(vaultType: Type): @KARATZ1XR82W.Vault {
206        return <- create Vault(balance: 0.0)
207    }
208
209    access(all) resource Administrator {
210        // createNewMinter
211        //
212        // Function that creates and returns a new minter resource
213        //
214        access(all) fun createNewMinter(): @Minter {
215            return <-create Minter()
216        }
217
218        /// Setup pricing parameters (only admin can call)
219        access(all) fun setupPricing(
220            maxSupply: UFix64,
221            initialSupply: UFix64,
222            initialPrice: UFix64,
223            reserveRatio: UFix64
224        ) {
225            KARATZ1XR82W.maxSupply = maxSupply
226            KARATZ1XR82W.initialSupply = initialSupply
227            KARATZ1XR82W.initialPrice = initialPrice
228            KARATZ1XR82W.reserveRatio = reserveRatio
229        }
230
231        /// Update pricing parameters (only admin can call)
232        access(all) fun updatePricing(
233            maxSupply: UFix64?,
234            initialSupply: UFix64?,
235            initialPrice: UFix64?,
236            reserveRatio: UFix64?
237        ) {
238            if maxSupply != nil {
239                KARATZ1XR82W.maxSupply = maxSupply!
240            }
241            if initialSupply != nil {
242                KARATZ1XR82W.initialSupply = initialSupply!
243            }
244            if initialPrice != nil {
245                KARATZ1XR82W.initialPrice = initialPrice!
246            }
247            if reserveRatio != nil {
248                KARATZ1XR82W.reserveRatio = reserveRatio!
249            }
250        }
251    }
252
253    /// Minter
254    ///
255    /// Resource object that token admin accounts can hold to mint new tokens.
256    ///
257    access(all) resource Minter {
258        /// mintTokens
259        ///
260        /// Function that mints new tokens, adds them to the total supply,
261        /// and returns them to the calling context.
262        ///
263        access(all) fun mintTokens(amount: UFix64, metadata: {String: String}?): @KARATZ1XR82W.Vault {
264            pre {
265                KARATZ1XR82W.totalSupply + amount <= KARATZ1XR82W.maxSupply: "Max supply exceeded"
266            }
267
268            KARATZ1XR82W.totalSupply = KARATZ1XR82W.totalSupply + amount
269
270            let eventData: {String: String} = {}
271            if metadata != nil {
272                for key in metadata!.keys {
273                    eventData[key] = metadata![key]
274                }
275            }
276
277            emit TokensMinted(amount: amount, type: self.getType().identifier, metadata: eventData)
278            return <-create Vault(balance: amount)
279        }
280    }
281
282    init() {
283        // Set our named paths.
284        self.VaultStoragePath = /storage/KARATZ1XR82WVault
285        self.ReceiverPublicPath = /public/KARATZ1XR82WReceiver
286        self.BalancePublicPath = /public/KARATZ1XR82WBalance
287        self.AdminStoragePath = /storage/KARATZ1XR82WAdmin
288
289        // Initialize contract state.
290        self.totalSupply = 0.0
291        // Set default pricing parameters
292        self.maxSupply = 2400000.0
293        self.initialSupply = 0.0
294        self.initialPrice = 1.0
295
296        self.reserveRatio = 0.0
297
298
299        // Create the Vault with the total supply of tokens and save it in storage
300        //
301        let vault <- create Vault(balance: self.totalSupply)
302
303        // Create a public capability to the stored Vault that exposes
304        // the `deposit` method and getAcceptedTypes method through the `Receiver` interface
305        // and the `balance` method through the `Balance` interface
306        //
307        let tokenCap = self.account.capabilities.storage.issue<&KARATZ1XR82W.Vault>(self.VaultStoragePath)
308        self.account.capabilities.publish(tokenCap, at: self.BalancePublicPath)
309        let receiverCap = self.account.capabilities.storage.issue<&KARATZ1XR82W.Vault>(self.VaultStoragePath)
310        self.account.capabilities.publish(receiverCap, at: self.ReceiverPublicPath)
311
312        self.account.storage.save(<-vault, to: self.VaultStoragePath)
313
314        let admin <- create Administrator()
315        self.account.storage.save(<-admin, to: self.AdminStoragePath)
316    }
317
318    access(all) fun emitBurnEvent(amount: UFix64, burner: Address, metadata: {String: String}?) {
319        emit TokensBurned(amount: amount, burner: burner, metadata: metadata ?? {})
320    }
321
322    /// Get pricing information
323    access(all) fun getPricingInfo(): {String: UFix64} {
324        return {
325            "maxSupply": self.maxSupply,
326            "initialSupply": self.initialSupply,
327            "initialPrice": self.initialPrice,
328            "reserveRatio": self.reserveRatio,
329            "totalSupply": self.totalSupply
330        }
331    }
332}