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