Smart Contract

TrollDAO

A.b055bef687cfca82.TrollDAO

Deployed

1d ago
Feb 25, 2026, 01:36:08 AM UTC

Dependents

1 imports
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