Smart Contract
Flowiykyk
A.01d63aa89238a559.Flowiykyk
1import FungibleToken from 0xf233dcee88fe0abe
2import FungibleTokenMetadataViews from 0xf233dcee88fe0abe
3import MetadataViews from 0x1d7e57aa55817448
4import Toucans from 0x577a3c409c5dcb5e
5import ToucansTokens from 0x577a3c409c5dcb5e
6
7pub contract Flowiykyk: FungibleToken {
8
9 // The amount of tokens in existance
10 pub var totalSupply: UFix64
11 // nil if there is none
12 pub let maxSupply: UFix64?
13
14 // Paths
15 pub let VaultStoragePath: StoragePath
16 pub let ReceiverPublicPath: PublicPath
17 pub let VaultPublicPath: PublicPath
18 pub let MinterStoragePath: StoragePath
19 pub let AdministratorStoragePath: StoragePath
20
21 // Events
22 pub event TokensInitialized(initialSupply: UFix64)
23 pub event TokensWithdrawn(amount: UFix64, from: Address?)
24 pub event TokensDeposited(amount: UFix64, to: Address?)
25 pub event TokensTransferred(amount: UFix64, from: Address, to: Address)
26 pub event TokensMinted(amount: UFix64)
27 pub event TokensBurned(amount: UFix64)
28
29 pub resource Vault: FungibleToken.Provider, FungibleToken.Receiver, FungibleToken.Balance, MetadataViews.Resolver {
30 pub var balance: UFix64
31
32 pub fun withdraw(amount: UFix64): @FungibleToken.Vault {
33 self.balance = self.balance - amount
34 emit TokensWithdrawn(amount: amount, from: self.owner?.address)
35
36 if let owner: Address = self.owner?.address {
37 Flowiykyk.setBalance(address: owner, balance: self.balance)
38 }
39 return <- create Vault(balance: amount)
40 }
41
42 pub fun deposit(from: @FungibleToken.Vault) {
43 let vault: @Vault <- from as! @Vault
44 self.balance = self.balance + vault.balance
45 emit TokensDeposited(amount: vault.balance, to: self.owner?.address)
46
47 // We set the balance to 0.0 here so that it doesn't
48 // decrease the totalSupply in the `destroy` function.
49 vault.balance = 0.0
50 destroy vault
51
52 if let owner: Address = self.owner?.address {
53 Flowiykyk.setBalance(address: owner, balance: self.balance)
54 }
55 }
56
57 pub fun getViews(): [Type]{
58 return [Type<FungibleTokenMetadataViews.FTView>(),
59 Type<FungibleTokenMetadataViews.FTDisplay>(),
60 Type<FungibleTokenMetadataViews.FTVaultData>()]
61 }
62
63 pub fun resolveView(_ view: Type): AnyStruct? {
64 switch view {
65 case Type<FungibleTokenMetadataViews.FTView>():
66 return FungibleTokenMetadataViews.FTView(
67 ftDisplay: self.resolveView(Type<FungibleTokenMetadataViews.FTDisplay>()) as! FungibleTokenMetadataViews.FTDisplay?,
68 ftVaultData: self.resolveView(Type<FungibleTokenMetadataViews.FTVaultData>()) as! FungibleTokenMetadataViews.FTVaultData?
69 )
70 case Type<FungibleTokenMetadataViews.FTDisplay>():
71 let media = MetadataViews.Media(
72 file: MetadataViews.HTTPFile(
73 url: "https://nftstorage.link/ipfs/bafkreic7ubmxctthynqlkxdsueu3j6vluibjewufklcf4qbl4slu5n5vh4"
74 ),
75 mediaType: "image"
76 )
77 let bannerMedia = MetadataViews.Media(
78 file: MetadataViews.HTTPFile(
79 url: "https://nftstorage.link/ipfs/bafkreidsefca7voeczhz57kkt5fjlel3x43wqwbrhfhweq3zbe7z5rtc5i"
80 ),
81 mediaType: "image"
82 )
83 let medias = MetadataViews.Medias([media, bannerMedia])
84 return FungibleTokenMetadataViews.FTDisplay(
85 name: "Flow iykyk",
86 symbol: "FIFI",
87 description: "I hope FIFI can achieve complete decentralization and explore the spirit of memes on the Flow blockchain. Therefore, I have set the total supply to 10^11 (can't get it larger lol, maybe due to the setting of toucans), ensuring that everyone will have a significant amount of FIFI.",
88 externalURL: MetadataViews.ExternalURL(""),
89 logos: medias,
90 socials: {
91 "twitter": MetadataViews.ExternalURL(""),
92 "discord": MetadataViews.ExternalURL("")
93 }
94 )
95 case Type<FungibleTokenMetadataViews.FTVaultData>():
96 return FungibleTokenMetadataViews.FTVaultData(
97 storagePath: Flowiykyk.VaultStoragePath,
98 receiverPath: Flowiykyk.ReceiverPublicPath,
99 metadataPath: Flowiykyk.VaultPublicPath,
100 providerPath: /private/FlowiykykVault,
101 receiverLinkedType: Type<&Vault{FungibleToken.Receiver}>(),
102 metadataLinkedType: Type<&Vault{FungibleToken.Balance, MetadataViews.Resolver}>(),
103 providerLinkedType: Type<&Vault{FungibleToken.Provider}>(),
104 createEmptyVaultFunction: (fun (): @Vault {
105 return <- Flowiykyk.createEmptyVault()
106 })
107 )
108 }
109 return nil
110 }
111
112 init(balance: UFix64) {
113 self.balance = balance
114 }
115
116 destroy() {
117 emit TokensBurned(amount: self.balance)
118 Flowiykyk.totalSupply = Flowiykyk.totalSupply - self.balance
119 }
120 }
121
122 pub fun createEmptyVault(): @Vault {
123 return <- create Vault(balance: 0.0)
124 }
125
126 pub resource Minter: Toucans.Minter {
127 pub fun mint(amount: UFix64): @Vault {
128 post {
129 Flowiykyk.maxSupply == nil || Flowiykyk.totalSupply <= Flowiykyk.maxSupply!:
130 "Exceeded the max supply of tokens allowd."
131 }
132 Flowiykyk.totalSupply = Flowiykyk.totalSupply + amount
133 emit TokensMinted(amount: amount)
134 return <- create Vault(balance: amount)
135 }
136 }
137
138 // We follow this pattern of storage
139 // so the (potentially) huge dictionary
140 // isn't loaded when the contract is imported
141 pub resource Administrator {
142 // This is an experimental index and should
143 // not be used for anything official
144 // or monetary related
145 access(self) let balances: {Address: UFix64}
146
147 access(contract) fun setBalance(address: Address, balance: UFix64) {
148 self.balances[address] = balance
149 }
150
151 pub fun getBalance(address: Address): UFix64 {
152 return self.balances[address] ?? 0.0
153 }
154
155 pub fun getBalances(): {Address: UFix64} {
156 return self.balances
157 }
158
159 init() {
160 self.balances = {}
161 }
162 }
163
164 access(contract) fun setBalance(address: Address, balance: UFix64) {
165 let admin: &Administrator = self.account.borrow<&Administrator>(from: self.AdministratorStoragePath)!
166 admin.setBalance(address: address, balance: balance)
167 }
168
169 pub fun getBalance(address: Address): UFix64 {
170 let admin: &Administrator = self.account.borrow<&Administrator>(from: self.AdministratorStoragePath)!
171 return admin.getBalance(address: address)
172 }
173
174 pub fun getBalances(): {Address: UFix64} {
175 let admin: &Administrator = self.account.borrow<&Administrator>(from: self.AdministratorStoragePath)!
176 return admin.getBalances()
177 }
178
179 init(
180 _paymentTokenInfo: ToucansTokens.TokenInfo,
181 _editDelay: UFix64,
182 _minting: Bool,
183 _initialTreasurySupply: UFix64,
184 _maxSupply: UFix64?,
185 _extra: {String: AnyStruct}
186 ) {
187
188 // Contract Variables
189 self.totalSupply = 0.0
190 self.maxSupply = _maxSupply
191
192 // Paths
193 self.VaultStoragePath = /storage/FlowiykykVault
194 self.ReceiverPublicPath = /public/FlowiykykReceiver
195 self.VaultPublicPath = /public/FlowiykykMetadata
196 self.MinterStoragePath = /storage/FlowiykykMinter
197 self.AdministratorStoragePath = /storage/FlowiykykAdmin
198
199 // Admin Setup
200 let vault <- create Vault(balance: self.totalSupply)
201 self.account.save(<- vault, to: self.VaultStoragePath)
202
203 self.account.link<&Vault{FungibleToken.Receiver}>(
204 self.ReceiverPublicPath,
205 target: self.VaultStoragePath
206 )
207
208 self.account.link<&Vault{FungibleToken.Balance, MetadataViews.Resolver}>(
209 self.VaultPublicPath,
210 target: self.VaultStoragePath
211 )
212
213 if self.account.borrow<&Toucans.Collection>(from: Toucans.CollectionStoragePath) == nil {
214 self.account.save(<- Toucans.createCollection(), to: Toucans.CollectionStoragePath)
215 self.account.link<&Toucans.Collection{Toucans.CollectionPublic}>(Toucans.CollectionPublicPath, target: Toucans.CollectionStoragePath)
216 }
217
218 let toucansProjectCollection = self.account.borrow<&Toucans.Collection>(from: Toucans.CollectionStoragePath)!
219 toucansProjectCollection.createProject(
220 projectTokenInfo: ToucansTokens.TokenInfo("Flowiykyk", self.account.address, "FIFI", self.ReceiverPublicPath, self.VaultPublicPath, self.VaultStoragePath),
221 paymentTokenInfo: _paymentTokenInfo,
222 minter: <- create Minter(),
223 editDelay: _editDelay,
224 minting: _minting,
225 initialTreasurySupply: _initialTreasurySupply,
226 extra: _extra
227 )
228
229 self.account.save(<- create Administrator(), to: self.AdministratorStoragePath)
230
231 // Events
232 emit TokensInitialized(initialSupply: self.totalSupply)
233 }
234}
235