Smart Contract

JPY24

A.215f3ac76cb49656.JPY24

Valid From

129,299,642

Deployed

1w ago
Feb 16, 2026, 05:30:15 AM UTC

Dependents

26 imports
1import MetadataViews from 0x1d7e57aa55817448
2import FungibleToken from 0xf233dcee88fe0abe
3import FungibleTokenMetadataViews from 0xf233dcee88fe0abe
4
5access(all) contract JPY24: 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 JPY24 tokens in existence
30    access(all) var totalSupply: UFix64
31
32    /// Storage and Public Paths
33    access(all) let VaultStoragePath: StoragePath
34    access(all) let BalancePublicPath: PublicPath
35    access(all) let ReceiverPublicPath: PublicPath
36    access(all) let AdminStoragePath: StoragePath
37
38    access(all) view fun getContractViews(resourceType: Type?): [Type] {
39        return [
40            Type<FungibleTokenMetadataViews.FTView>(),
41            Type<FungibleTokenMetadataViews.FTDisplay>(),
42            Type<FungibleTokenMetadataViews.FTVaultData>(),
43            Type<FungibleTokenMetadataViews.TotalSupply>()
44        ]
45    }
46
47    access(all) fun resolveContractView(resourceType: Type?, viewType: Type): AnyStruct? {
48        switch viewType {
49            case Type<FungibleTokenMetadataViews.FTView>():
50                return FungibleTokenMetadataViews.FTView(
51                    ftDisplay: self.resolveContractView(resourceType: nil, viewType: Type<FungibleTokenMetadataViews.FTDisplay>()) as! FungibleTokenMetadataViews.FTDisplay?,
52                    ftVaultData: self.resolveContractView(resourceType: nil, viewType: Type<FungibleTokenMetadataViews.FTVaultData>()) as! FungibleTokenMetadataViews.FTVaultData?
53                )
54            case Type<FungibleTokenMetadataViews.FTDisplay>():
55                let media = MetadataViews.Media(
56                    file: MetadataViews.HTTPFile(
57                        url: "https://24karat.io/tokens/JPY24/thumbnail.png"
58                    ),
59                    mediaType: "image/png"
60                )
61                return FungibleTokenMetadataViews.FTDisplay(
62                    name: "JPY24 Token",
63                    symbol: "JPY24",
64                    description: "JPY24 Token - Japanese Yen backed digital token",
65                    externalURL: MetadataViews.ExternalURL("https://24karat.io"),
66                    logos: MetadataViews.Medias([media]),
67                    socials: {}
68                )
69            case Type<FungibleTokenMetadataViews.FTVaultData>():
70                return FungibleTokenMetadataViews.FTVaultData(
71                    storagePath: self.VaultStoragePath,
72                    receiverPath: self.ReceiverPublicPath,
73                    metadataPath: self.BalancePublicPath,
74                    receiverLinkedType: Type<&JPY24.Vault>(),
75                    metadataLinkedType: Type<&JPY24.Vault>(),
76                    createEmptyVaultFunction: (fun(): @{FungibleToken.Vault} {
77                        return <-JPY24.createEmptyVault(vaultType: Type<@JPY24.Vault>())
78                    })
79                )
80            case Type<FungibleTokenMetadataViews.TotalSupply>():
81                return FungibleTokenMetadataViews.TotalSupply(
82                    totalSupply: JPY24.totalSupply
83                )
84        }
85        return nil
86    }
87
88    /// Vault
89    ///
90    /// Each user stores an instance of only the Vault in their storage
91    /// The functions in the Vault and governed by the pre and post conditions
92    /// in FungibleToken when they are called.
93    /// The checks happen at runtime whenever a function is called.
94    ///
95    /// Resources can only be created in the context of the contract that they
96    /// are defined in, so there is no way for a malicious user to create Vaults
97    /// out of thin air. A special Minter resource needs to be defined to mint
98    /// new tokens.
99    ///
100    access(all) resource Vault: FungibleToken.Vault {
101
102        /// The total balance of this vault
103        access(all) var balance: UFix64
104
105        // initialize the balance at resource creation time
106        init(balance: UFix64) {
107            self.balance = balance
108        }
109
110        /// Called when a fungible token is burned via the `Burner.burn()` method
111        access(contract) fun burnCallback() {
112            if self.balance > 0.0 {
113                JPY24.totalSupply = JPY24.totalSupply - self.balance
114            }
115            self.balance = 0.0
116        }
117
118        access(all) view fun getViews(): [Type] {
119            return JPY24.getContractViews(resourceType: nil)
120        }
121
122        access(all) fun resolveView(_ view: Type): AnyStruct? {
123            return JPY24.resolveContractView(resourceType: nil, viewType: view)
124        }
125
126        /// getSupportedVaultTypes optionally returns a list of vault types that this receiver accepts
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        /// Asks if the amount can be withdrawn from this vault
138        access(all) view fun isAvailableToWithdraw(amount: UFix64): Bool {
139            return amount <= self.balance
140        }
141
142        /// withdraw
143        ///
144        /// Function that takes an amount as an argument
145        /// and withdraws that amount from the Vault.
146        ///
147        /// It creates a new temporary Vault that is used to hold
148        /// the tokens that are being transferred. It returns the newly
149        /// created Vault to the context that called so it can be deposited
150        /// elsewhere.
151        ///
152        access(FungibleToken.Withdraw) fun withdraw(amount: UFix64): @JPY24.Vault {
153            self.balance = self.balance - amount
154            return <-create Vault(balance: amount)
155        }
156
157        /// deposit
158        ///
159        /// Function that takes a Vault object as an argument and adds
160        /// its balance to the balance of the owners Vault.
161        ///
162        /// It is allowed to destroy the sent Vault because the Vault
163        /// was a temporary holder of the tokens. The Vault's balance has
164        /// been consumed and therefore can be destroyed.
165        ///
166        access(all) fun deposit(from: @{FungibleToken.Vault}) {
167            let vault <- from as! @JPY24.Vault
168            self.balance = self.balance + vault.balance
169            vault.balance = 0.0
170            destroy vault
171        }
172
173        /// createEmptyVault
174        ///
175        /// Function that creates a new Vault with a balance of zero
176        /// and returns it to the calling context. A user must call this function
177        /// and store the returned Vault in their storage in order to allow their
178        /// account to be able to receive deposits of this token type.
179        ///
180        access(all) fun createEmptyVault(): @JPY24.Vault {
181            return <-create Vault(balance: 0.0)
182        }
183    }
184
185    /// createEmptyVault
186    ///
187    /// Function that creates a new Vault with a balance of zero
188    /// and returns it to the calling context. A user must call this function
189    /// and store the returned Vault in their storage in order to allow their
190    /// account to be able to receive deposits of this token type.
191    ///
192    access(all) fun createEmptyVault(vaultType: Type): @JPY24.Vault {
193        return <- create Vault(balance: 0.0)
194    }
195
196    access(all) resource Administrator {
197        // createNewMinter
198        //
199        // Function that creates and returns a new minter resource
200        //
201        access(all) fun createNewMinter(): @Minter {
202            return <-create Minter()
203        }
204    }
205
206    /// Minter
207    ///
208    /// Resource object that token admin accounts can hold to mint new tokens.
209    ///
210    access(all) resource Minter {
211        /// mintTokens
212        ///
213        /// Function that mints new tokens, adds them to the total supply,
214        /// and returns them to the calling context.
215        ///
216        access(all) fun mintTokens(amount: UFix64, metadata: {String: String}?): @JPY24.Vault {
217            JPY24.totalSupply = JPY24.totalSupply + amount
218
219            let eventData: {String: String} = {}
220            if metadata != nil {
221                for key in metadata!.keys {
222                    eventData[key] = metadata![key]
223                }
224            }
225
226            emit TokensMinted(amount: amount, type: self.getType().identifier, metadata: eventData)
227            return <-create Vault(balance: amount)
228        }
229    }
230
231    init() {
232        // Set our named paths.
233        self.VaultStoragePath = /storage/jpy24Vault
234        self.ReceiverPublicPath = /public/jpy24Receiver
235        self.BalancePublicPath = /public/jpy24Balance
236        self.AdminStoragePath = /storage/jpy24Admin
237
238        // Initialize contract state.
239        self.totalSupply = 0.0
240
241        // Create the Vault with the total supply of tokens and save it in storage
242        //
243        let vault <- create Vault(balance: self.totalSupply)
244
245        // Create a public capability to the stored Vault that exposes
246        // the `deposit` method and getAcceptedTypes method through the `Receiver` interface
247        // and the `balance` method through the `Balance` interface
248        //
249        let tokenCap = self.account.capabilities.storage.issue<&JPY24.Vault>(self.VaultStoragePath)
250        self.account.capabilities.publish(tokenCap, at: self.BalancePublicPath)
251        let receiverCap = self.account.capabilities.storage.issue<&JPY24.Vault>(self.VaultStoragePath)
252        self.account.capabilities.publish(receiverCap, at: self.ReceiverPublicPath)
253
254        self.account.storage.save(<-vault, to: self.VaultStoragePath)
255
256        let admin <- create Administrator()
257        self.account.storage.save(<-admin, to: self.AdminStoragePath)
258    }
259
260    access(all) fun emitBurnEvent(amount: UFix64, burner: Address, metadata: {String: String}?) {
261        emit TokensBurned(amount: amount, burner: burner, metadata: metadata ?? {})
262    }
263}
264