Smart Contract

XpToken

A.66b60643244a7738.XpToken

Valid From

87,008,784

Deployed

3d ago
Feb 24, 2026, 11:37:59 PM UTC

Dependents

7 imports
1/// Testnet
2/// import FungibleToken from 0x9a0766d93b6608b7
3
4/// Mainnet
5import FungibleToken from 0xf233dcee88fe0abe
6import MetadataViews from 0x1d7e57aa55817448
7import FungibleTokenMetadataViews from 0xf233dcee88fe0abe
8
9
10
11access(all) contract XpToken: FungibleToken {
12
13    access(all) var totalSupply: UFix64
14
15    access(all) let VaultReceiverPath: PublicPath
16    access(all) let VaultBalancePath: PublicPath
17    access(all) let VaultStoragePath: StoragePath
18    access(all) let AdminStoragePath: StoragePath
19
20    access(all) event TokensInitialized(initialSupply: UFix64)
21    access(all) event TokensWithdrawn(amount: UFix64, from: Address?)
22    access(all) event TokensDeposited(amount: UFix64, to: Address?)
23    access(all) event TokensMinted(amount: UFix64)
24    access(all) event TokensBurned(amount: UFix64)
25    access(all) event MinterCreated(allowedAmount: UFix64)
26    access(all) event BurnerCreated()
27
28    access(all) view fun getContractViews(resourceType: Type?): [Type] {
29        return [
30            Type<FungibleTokenMetadataViews.FTView>(),
31            Type<FungibleTokenMetadataViews.FTDisplay>(),
32            Type<FungibleTokenMetadataViews.FTVaultData>(),
33            Type<FungibleTokenMetadataViews.TotalSupply>()
34        ]
35    }
36
37        access(all) fun resolveContractView(resourceType: Type?, viewType: Type): AnyStruct? {
38        switch viewType {
39            case Type<FungibleTokenMetadataViews.FTView>():
40                return FungibleTokenMetadataViews.FTView(
41                    ftDisplay: self.resolveContractView(resourceType: nil, viewType: Type<FungibleTokenMetadataViews.FTDisplay>()) as! FungibleTokenMetadataViews.FTDisplay?,
42                    ftVaultData: self.resolveContractView(resourceType: nil, viewType: Type<FungibleTokenMetadataViews.FTVaultData>()) as! FungibleTokenMetadataViews.FTVaultData?
43                )
44            case Type<FungibleTokenMetadataViews.FTDisplay>():
45                let media = MetadataViews.Media(
46                        file: MetadataViews.HTTPFile(
47                        url: "https://imgur.com/IG75YJ2.png"
48                    ),
49                    mediaType: "image/png+xml"
50                )
51                let medias = MetadataViews.Medias([media])
52                return FungibleTokenMetadataViews.FTDisplay(
53                    name: "XP Token",
54                    symbol: "XP",
55                    description: "XP Token",
56                    externalURL: MetadataViews.ExternalURL("https://titpalace.xyz"),
57                    logos: medias,
58                    socials: {
59                        "twitter": MetadataViews.ExternalURL("https://x.com/vertico_defi"),
60                        "instagram": MetadataViews.ExternalURL("https://www.instagram.com/titpalace/")
61                    }
62                )
63            case Type<FungibleTokenMetadataViews.FTVaultData>():
64                return FungibleTokenMetadataViews.FTVaultData(
65                    storagePath: self.VaultStoragePath,
66                    receiverPath: self.VaultReceiverPath,
67                    metadataPath: self.VaultBalancePath,
68                    receiverLinkedType: Type<&Vault>(),
69                    metadataLinkedType: Type<&Vault>(),
70                    createEmptyVaultFunction: (fun(): @{FungibleToken.Vault} {
71                        return <- XpToken.createEmptyVault(vaultType: Type<@Vault>())
72                    })
73                )
74            case Type<FungibleTokenMetadataViews.TotalSupply>():
75                return FungibleTokenMetadataViews.TotalSupply(
76                    totalSupply: XpToken.totalSupply
77                )
78        }
79        return nil
80    }
81
82    access(all) resource Vault: FungibleToken.Vault {
83
84        access(all) var balance: UFix64
85
86        init(balance: UFix64) {
87            self.balance = balance
88        }
89
90        access(contract) fun burnCallback() {
91            if self.balance > 0.0 {
92                XpToken.totalSupply = XpToken.totalSupply - self.balance
93            }
94            self.balance = 0.0
95        }
96
97        access(all) view fun getViews(): [Type] {
98            return XpToken.getContractViews(resourceType: nil)
99        }
100
101        access(all) fun resolveView(_ view: Type): AnyStruct? {
102            return XpToken.resolveContractView(resourceType: nil, viewType: view)
103        }
104
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        access(all) view fun isAvailableToWithdraw(amount: UFix64): Bool {
116            return amount <= self.balance
117        }
118
119        access(all) fun withdraw(amount: UFix64): @Vault {
120            self.balance = self.balance - amount
121            return <- create Vault(balance: amount)
122        }
123
124        access(all) fun deposit(from: @{FungibleToken.Vault}) {
125            let vault <- from as! @XpToken.Vault
126            self.balance = self.balance + vault.balance
127            vault.balance = 0.0
128            destroy vault
129        }
130
131        access(all) fun createEmptyVault(): @Vault {
132            return <-create Vault(balance: 0.0)
133        }
134
135    }
136
137    access(all) fun createEmptyVault(vaultType: Type): @Vault {
138        return <- create Vault(balance: 0.0)
139    }
140
141    access(all) resource Minter {
142
143        access(all) var allowedAmount: UFix64
144
145        access(all) fun mintTokens(amount: UFix64): @XpToken.Vault {
146            pre {
147                amount > 0.0: "Amount minted must be greater than zero"
148                amount <= self.allowedAmount: "Amount minted must be less than the allowed amount"
149            }
150            XpToken.totalSupply = XpToken.totalSupply + amount
151            self.allowedAmount = self.allowedAmount - amount
152            emit TokensMinted(amount: amount)
153            return <- create Vault(balance: amount)
154        }
155
156        init(allowedAmount: UFix64) {
157            self.allowedAmount = allowedAmount
158        }
159
160    }
161
162    access(all) resource Burner {}
163
164    access(all) resource Administrator {
165
166        access(all) fun createNewMinter(allowedAmount: UFix64): @Minter {
167            emit MinterCreated(allowedAmount: allowedAmount)
168            return <- create Minter(allowedAmount: allowedAmount)
169        }
170
171    }
172
173    init() {
174        self.totalSupply = 444444444.0
175
176        self.VaultReceiverPath = /public/XpTokenReceiver
177        self.VaultBalancePath = /public/XpTokenBalance
178        self.VaultStoragePath = /storage/XpTokenVault
179        self.AdminStoragePath = /storage/XpTokenAdmin
180
181        let vault <- create Vault(balance: self.totalSupply)
182        emit TokensMinted(amount: vault.balance)
183
184        let exampleTokenCap = self.account.capabilities.storage.issue<&Vault>(self.VaultStoragePath)
185        self.account.capabilities.publish(exampleTokenCap, at: self.VaultBalancePath)
186        let receiverCap = self.account.capabilities.storage.issue<&Vault>(self.VaultStoragePath)
187        self.account.capabilities.publish(receiverCap, at: self.VaultReceiverPath)
188
189        self.account.storage.save(<-vault, to: self.VaultStoragePath)
190
191        let admin <- create Administrator()
192        self.account.storage.save(<-admin, to: self.AdminStoragePath)
193    }
194}
195
196