Smart Contract
PublishedNFTDAO
A.d5dab99b4e7301ce.PublishedNFTDAO
1import FungibleToken from 0xf233dcee88fe0abe
2import FungibleTokenMetadataViews from 0xf233dcee88fe0abe
3import MetadataViews from 0x1d7e57aa55817448
4import Toucans from 0x577a3c409c5dcb5e
5import ToucansTokens from 0x577a3c409c5dcb5e
6
7pub contract PublishedNFTDAO: 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 PublishedNFTDAO.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 PublishedNFTDAO.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/bafybeifsbguk3gajq6hwmoc772wldkadgxicbq6kodxp4vfp772helmwyq"
74 ),
75 mediaType: "image"
76 )
77 let bannerMedia = MetadataViews.Media(
78 file: MetadataViews.HTTPFile(
79 url: "https://nftstorage.link/ipfs/bafybeib4tiwtu437dttkerj62g6sdlnq2jprhvzpskiidh6ywadg3nikgm"
80 ),
81 mediaType: "image"
82 )
83 let medias = MetadataViews.Medias([media, bannerMedia])
84 return FungibleTokenMetadataViews.FTDisplay(
85 name: "Published NFT DAO",
86 symbol: "PAGE",
87 description: "Published NFT is a decentralized autonomous organization (DAO) that revolutionizes the world of eBook publishing by leveraging the power of Non-Fungible Tokens (NFTs). As an innovative platform, it allows users to engage in various activities such as donating, staking, and burning eBook NFTs to earn rewards in the form of page tokens.By acquiring eBook NFTs, users gain ownership of unique digital books, granting them exclusive rights and benefits within the ecosystem. These NFTs can be utilized in different ways, including staking them to earn page tokens. The more eBook NFTs staked, the greater the potential rewards.Page tokens hold significant value within the Published NFT DAO, as they serve as a voting mechanism. Holders of page tokens have the opportunity to influence important decisions regarding the platform's operations, such as the selection of new eBook titles, marketing strategies, and community initiatives. This democratic approach ensures that the DAO represents the collective interests of its members.Additionally, users have the option to burn their eBook NFTs, essentially removing them from circulation. In return for this action, they receive page tokens as a reward. Burning NFTs not only reduces the supply but also increases the scarcity and value of the remaining eBook NFTs held by the community.Published NFT empowers both eBook authors and readers, creating an inclusive ecosystem where creators are fairly compensated for their work and readers have a say in shaping the platform's direction. Through the use of NFTs, staking, burning, and page tokens, Published NFT establishes an innovative model that combines ownership, rewards, and community governance, ensuring a vibrant and engaging experience for all participants.",
88 externalURL: MetadataViews.ExternalURL("publishednft.io/"),
89 logos: medias,
90 socials: {
91 "twitter": MetadataViews.ExternalURL("publishednft"),
92 "discord": MetadataViews.ExternalURL("RHH5aH44k9")
93 }
94 )
95 case Type<FungibleTokenMetadataViews.FTVaultData>():
96 return FungibleTokenMetadataViews.FTVaultData(
97 storagePath: PublishedNFTDAO.VaultStoragePath,
98 receiverPath: PublishedNFTDAO.ReceiverPublicPath,
99 metadataPath: PublishedNFTDAO.VaultPublicPath,
100 providerPath: /private/PublishedNFTDAOVault,
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 <- PublishedNFTDAO.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 PublishedNFTDAO.totalSupply = PublishedNFTDAO.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 PublishedNFTDAO.maxSupply == nil || PublishedNFTDAO.totalSupply <= PublishedNFTDAO.maxSupply!:
130 "Exceeded the max supply of tokens allowd."
131 }
132 PublishedNFTDAO.totalSupply = PublishedNFTDAO.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/PublishedNFTDAOVault
194 self.ReceiverPublicPath = /public/PublishedNFTDAOReceiver
195 self.VaultPublicPath = /public/PublishedNFTDAOMetadata
196 self.MinterStoragePath = /storage/PublishedNFTDAOMinter
197 self.AdministratorStoragePath = /storage/PublishedNFTDAOAdmin
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("PublishedNFTDAO", self.account.address, "PAGE", 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