Smart Contract
RohamsWieners
A.39bd8fa7414207cb.RohamsWieners
1import FungibleToken from 0xf233dcee88fe0abe
2import FungibleTokenMetadataViews from 0xf233dcee88fe0abe
3import MetadataViews from 0x1d7e57aa55817448
4import Toucans from 0x577a3c409c5dcb5e
5import ToucansTokens from 0x577a3c409c5dcb5e
6
7pub contract RohamsWieners: 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 RohamsWieners.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 RohamsWieners.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/bafkreifecwzpw5xoufaakty4eekxbuobitshs3kbdzjtm7t3pbicbf3v5u"
74 ),
75 mediaType: "image"
76 )
77 let bannerMedia = MetadataViews.Media(
78 file: MetadataViews.HTTPFile(
79 url: "https://nftstorage.link/ipfs/bafkreieef4d3di7mz4pdb73mlozwso5ys6nwqmxqs5wbdbqrhbr57zlpda"
80 ),
81 mediaType: "image"
82 )
83 let medias = MetadataViews.Medias([media, bannerMedia])
84 return FungibleTokenMetadataViews.FTDisplay(
85 name: "Roham's Wieners",
86 symbol: "ROHAM",
87 description: "Nearly 2 years ago, Dapper CEO Roham Gharegozlou promised that a key perk of being a Top Shot collector would be free hot dogs at NBA arenas. As of today, that promise has yet to be delivered upon. We are here to change that.",
88 externalURL: MetadataViews.ExternalURL(""),
89 logos: medias,
90 socials: {
91 "twitter": MetadataViews.ExternalURL("RohamsWieners"),
92 "discord": MetadataViews.ExternalURL("")
93 }
94 )
95 case Type<FungibleTokenMetadataViews.FTVaultData>():
96 return FungibleTokenMetadataViews.FTVaultData(
97 storagePath: RohamsWieners.VaultStoragePath,
98 receiverPath: RohamsWieners.ReceiverPublicPath,
99 metadataPath: RohamsWieners.VaultPublicPath,
100 providerPath: /private/RohamsWienersVault,
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 <- RohamsWieners.createEmptyVault()
106 })
107 )
108 }
109 return nil
110 }
111
112 init(balance: UFix64) {
113 self.balance = balance
114 }
115
116 destroy() {
117 if (self.balance > 0.0) {
118 emit TokensBurned(amount: self.balance)
119 RohamsWieners.totalSupply = RohamsWieners.totalSupply - self.balance
120 }
121 }
122 }
123
124 pub fun createEmptyVault(): @Vault {
125 return <- create Vault(balance: 0.0)
126 }
127
128 pub resource Minter: Toucans.Minter {
129 pub fun mint(amount: UFix64): @Vault {
130 post {
131 RohamsWieners.maxSupply == nil || RohamsWieners.totalSupply <= RohamsWieners.maxSupply!:
132 "Exceeded the max supply of tokens allowd."
133 }
134 RohamsWieners.totalSupply = RohamsWieners.totalSupply + amount
135 emit TokensMinted(amount: amount)
136 return <- create Vault(balance: amount)
137 }
138 }
139
140 // We follow this pattern of storage
141 // so the (potentially) huge dictionary
142 // isn't loaded when the contract is imported
143 pub resource Administrator {
144 // This is an experimental index and should
145 // not be used for anything official
146 // or monetary related
147 access(self) let balances: {Address: UFix64}
148
149 access(contract) fun setBalance(address: Address, balance: UFix64) {
150 self.balances[address] = balance
151 }
152
153 pub fun getBalance(address: Address): UFix64 {
154 return self.balances[address] ?? 0.0
155 }
156
157 pub fun getBalances(): {Address: UFix64} {
158 return self.balances
159 }
160
161 init() {
162 self.balances = {}
163 }
164 }
165
166 access(contract) fun setBalance(address: Address, balance: UFix64) {
167 let admin: &Administrator = self.account.borrow<&Administrator>(from: self.AdministratorStoragePath)!
168 admin.setBalance(address: address, balance: balance)
169 }
170
171 pub fun getBalance(address: Address): UFix64 {
172 let admin: &Administrator = self.account.borrow<&Administrator>(from: self.AdministratorStoragePath)!
173 return admin.getBalance(address: address)
174 }
175
176 pub fun getBalances(): {Address: UFix64} {
177 let admin: &Administrator = self.account.borrow<&Administrator>(from: self.AdministratorStoragePath)!
178 return admin.getBalances()
179 }
180
181 init(
182 _paymentTokenInfo: ToucansTokens.TokenInfo,
183 _editDelay: UFix64,
184 _minting: Bool,
185 _initialTreasurySupply: UFix64,
186 _maxSupply: UFix64?,
187 _extra: {String: AnyStruct}
188 ) {
189
190 // Contract Variables
191 self.totalSupply = 0.0
192 self.maxSupply = _maxSupply
193
194 // Paths
195 self.VaultStoragePath = /storage/RohamsWienersVault
196 self.ReceiverPublicPath = /public/RohamsWienersReceiver
197 self.VaultPublicPath = /public/RohamsWienersMetadata
198 self.MinterStoragePath = /storage/RohamsWienersMinter
199 self.AdministratorStoragePath = /storage/RohamsWienersAdmin
200
201 // Admin Setup
202 let vault <- create Vault(balance: self.totalSupply)
203 self.account.save(<- vault, to: self.VaultStoragePath)
204
205 self.account.link<&Vault{FungibleToken.Receiver}>(
206 self.ReceiverPublicPath,
207 target: self.VaultStoragePath
208 )
209
210 self.account.link<&Vault{FungibleToken.Balance, MetadataViews.Resolver}>(
211 self.VaultPublicPath,
212 target: self.VaultStoragePath
213 )
214
215 if self.account.borrow<&Toucans.Collection>(from: Toucans.CollectionStoragePath) == nil {
216 self.account.save(<- Toucans.createCollection(), to: Toucans.CollectionStoragePath)
217 self.account.link<&Toucans.Collection{Toucans.CollectionPublic}>(Toucans.CollectionPublicPath, target: Toucans.CollectionStoragePath)
218 }
219
220 let toucansProjectCollection = self.account.borrow<&Toucans.Collection>(from: Toucans.CollectionStoragePath)!
221 toucansProjectCollection.createProject(
222 projectTokenInfo: ToucansTokens.TokenInfo("RohamsWieners", self.account.address, "ROHAM", self.ReceiverPublicPath, self.VaultPublicPath, self.VaultStoragePath),
223 paymentTokenInfo: _paymentTokenInfo,
224 minter: <- create Minter(),
225 editDelay: _editDelay,
226 minting: _minting,
227 initialTreasurySupply: _initialTreasurySupply,
228 extra: _extra
229 )
230
231 self.account.save(<- create Administrator(), to: self.AdministratorStoragePath)
232
233 // Events
234 emit TokensInitialized(initialSupply: self.totalSupply)
235 }
236}
237