Smart Contract

NWayUtilityCoin

A.011b6f1425389550.NWayUtilityCoin

Deployed

4d ago
Feb 24, 2026, 09:04:31 AM UTC

Dependents

4 imports
1import FungibleToken from 0xf233dcee88fe0abe
2import FungibleTokenMetadataViews from 0xf233dcee88fe0abe
3import MetadataViews from 0x1d7e57aa55817448
4
5access(all)
6contract NWayUtilityCoin: FungibleToken { 
7	
8	// Total supply of NWayUtilityCoins in existence
9	access(all)
10	var totalSupply: UFix64
11	
12	
13	// Event that is emitted when tokens are withdrawn from a Vault
14	access(all)
15	event TokensWithdrawn(amount: UFix64, from: Address?)
16	
17	// Event that is emitted when tokens are deposited to a Vault
18	access(all)
19	event TokensDeposited(amount: UFix64, to: Address?)
20	
21	// Event that is emitted when new tokens are minted
22	access(all)
23	event TokensMinted(amount: UFix64)
24	
25	// Event that is emitted when tokens are destroyed
26	access(all)
27	event TokensBurned(amount: UFix64)
28	
29	// Event that is emitted when a new minter resource is created
30	access(all)
31	event MinterCreated(allowedAmount: UFix64)
32	
33	// Event that is emitted when a new burner resource is created
34	access(all)
35	event BurnerCreated()
36	
37	// Path where the `token Vault` is stored
38	access(all)
39	let VaultStoragePath: StoragePath
40	
41	// Path where the `token Admin` is stored
42	access(all)
43	let AdminStoragePath: StoragePath
44	
45	// Path where the public capability for the `token balance` is
46    access(all)
47    let TokenBalancePublicPath: PublicPath
48    
49	// Path where the public capability for the `token receiver` is
50	access(all)
51	let TokenReceiverPublicPath: PublicPath
52	
53	// Vault
54	//
55	// Each user stores an instance of only the Vault in their storage
56	// The functions in the Vault and governed by the pre and post conditions
57	// in FungibleToken when they are called.
58	// The checks happen at runtime whenever a function is called.
59	//
60	// Resources can only be created in the context of the contract that they
61	// are defined in, so there is no way for a malicious user to create Vaults
62	// out of thin air. A special Minter resource needs to be defined to mint
63	// new tokens.
64	//
65	access(all)
66	resource Vault: FungibleToken.Vault { 
67        access(all) event ResourceDestroyed(id: UInt64 = self.uuid, balance: UFix64 = self.balance)
68		
69		// holds the balance of a users tokens
70		access(all)
71		var balance: UFix64
72		
73		// initialize the balance at resource creation time
74		init(balance: UFix64){ 
75			self.balance = balance
76		}
77		
78        /// Called when a fungible token is burned via the `Burner.burn()` method
79        access(contract) fun burnCallback() {
80            if self.balance > 0.0 {
81                NWayUtilityCoin.totalSupply = NWayUtilityCoin.totalSupply - self.balance
82            }
83            self.balance = 0.0
84        }
85
86       /// Asks if the amount can be withdrawn from this vault
87        access(all) view fun isAvailableToWithdraw(amount: UFix64): Bool {
88            return amount <= self.balance
89        }
90
91        access(all) view fun getViews(): [Type] {
92            return NWayUtilityCoin.getContractViews(resourceType: nil)
93        }
94
95        access(all) fun resolveView(_ view: Type): AnyStruct? {
96            return NWayUtilityCoin.resolveContractView(resourceType: nil, viewType: view)
97        }
98
99        /// Get the balance of the vault
100        access(all) view fun getBalance(): UFix64 {
101            return self.balance
102        }
103
104		// withdraw
105		//
106		// Function that takes an integer amount as an argument
107		// and withdraws that amount from the Vault.
108		// It creates a new temporary Vault that is used to hold
109		// the money that is being transferred. It returns the newly
110		// created Vault to the context that called so it can be deposited
111		// elsewhere.
112		//
113		access(FungibleToken.Withdraw)
114		fun withdraw(amount: UFix64): @NWayUtilityCoin.Vault{ 
115			self.balance = self.balance - amount
116			emit TokensWithdrawn(amount: amount, from: self.owner?.address)
117			return <-create Vault(balance: amount)
118		}
119		
120		// deposit
121		//
122		// Function that takes a Vault object as an argument and adds
123		// its balance to the balance of the owners Vault.
124		// It is allowed to destroy the sent Vault because the Vault
125		// was a temporary holder of the tokens. The Vault's balance has
126		// been consumed and therefore can be destroyed.
127		access(all)
128		fun deposit(from: @{FungibleToken.Vault}): Void{ 
129			let vault <- from as! @NWayUtilityCoin.Vault
130			self.balance = self.balance + vault.balance
131			emit TokensDeposited(amount: vault.balance, to: self.owner?.address)
132			vault.balance = 0.0
133			destroy vault
134		}
135        /// Returns the storage path where the vault should typically be stored
136        access(all) view fun getDefaultStoragePath(): StoragePath? {
137            return /storage/NWayUtilityCoinVault
138        }
139
140        /// Returns the public path where this vault should have a public capability
141        access(all) view fun getDefaultPublicPath(): PublicPath? {
142            return /public/dapperUtilityCoinVault
143        }
144		
145        /// Returns the public path where this vault's Receiver should have a public capability
146        access(all) view fun getDefaultReceiverPath(): PublicPath? {
147            return nil
148        }
149
150       access(all) fun createEmptyVault(): @NWayUtilityCoin.Vault {
151			return <-create Vault(balance: 0.0)
152		}
153	}
154	
155	// createEmptyVault
156	//
157	// Function that creates a new Vault with a balance of zero
158	// and returns it to the calling context. A user must call this function
159	// and store the returned Vault in their storage in order to allow their
160	// account to be able to receive deposits of this token type.
161	//
162	access(all)
163	fun createEmptyVault(vaultType: Type): @NWayUtilityCoin.Vault{ 
164		return <-create Vault(balance: 0.0)
165	}
166	
167	access(all)
168	resource Administrator{ 
169		// createNewMinter
170		//
171		// Function that creates and returns a new minter resource
172		//
173		access(all)
174		fun createNewMinter(allowedAmount: UFix64): @Minter{ 
175			emit MinterCreated(allowedAmount: allowedAmount)
176			return <-create Minter(allowedAmount: allowedAmount)
177		}
178		
179		// createNewBurner
180		//
181		// Function that creates and returns a new burner resource
182		//
183		access(all)
184		fun createNewBurner(): @Burner{ 
185			emit BurnerCreated()
186			return <-create Burner()
187		}
188	}
189	
190	// Minter
191	//
192	// Resource object that token admin accounts can hold to mint new tokens.
193	//
194	access(all)
195	resource Minter{ 
196		
197		// the amount of tokens that the minter is allowed to mint
198		access(all)
199		var allowedAmount: UFix64
200		
201		// mintTokens
202		//
203		// Function that mints new tokens, adds them to the total supply,
204		// and returns them to the calling context.
205		//
206		access(all)
207		fun mintTokens(amount: UFix64): @NWayUtilityCoin.Vault{ 
208			pre{ 
209				amount > UFix64(0):
210					"Amount minted must be greater than zero"
211				amount <= self.allowedAmount:
212					"Amount minted must be less than the allowed amount"
213			}
214			NWayUtilityCoin.totalSupply = NWayUtilityCoin.totalSupply + amount
215			self.allowedAmount = self.allowedAmount - amount
216			emit TokensMinted(amount: amount)
217			return <-create Vault(balance: amount)
218		}
219		
220		init(allowedAmount: UFix64){ 
221			self.allowedAmount = allowedAmount
222		}
223	}
224	
225	// Burner
226	//
227	// Resource object that token admin accounts can hold to burn tokens.
228	//
229	access(all)
230	resource Burner{ 
231		
232		// burnTokens
233		//
234		// Function that destroys a Vault instance, effectively burning the tokens.
235		//
236		// Note: the burned tokens are automatically subtracted from the
237		// total supply in the Vault destructor.
238		//
239		access(all)
240		fun burnTokens(from: @NWayUtilityCoin.Vault){ 
241			let vault <- from as! @NWayUtilityCoin.Vault
242			let amount = vault.balance
243			vault.burnCallback()
244			destroy vault
245			emit TokensBurned(amount: amount)
246		}
247	}
248	
249    access(all) view fun getContractViews(resourceType: Type?): [Type] {
250        return [
251            Type<FungibleTokenMetadataViews.FTVaultData>(),
252            Type<FungibleTokenMetadataViews.TotalSupply>()
253        ]
254    }
255
256    access(all) fun resolveContractView(resourceType: Type?, viewType: Type): AnyStruct? {
257        switch viewType {
258            case Type<FungibleTokenMetadataViews.FTVaultData>():
259                return FungibleTokenMetadataViews.FTVaultData(
260                    storagePath: self.VaultStoragePath,
261                    receiverPath: self.TokenReceiverPublicPath,
262                    metadataPath: self.TokenBalancePublicPath,
263                    receiverLinkedType: Type<&NWayUtilityCoin.Vault>(),
264                    metadataLinkedType: Type<&NWayUtilityCoin.Vault>(),
265                    createEmptyVaultFunction: (fun(): @{FungibleToken.Vault} {
266                        return <-NWayUtilityCoin.createEmptyVault(vaultType: Type<@NWayUtilityCoin.Vault>())
267                    })
268                )
269            case Type<FungibleTokenMetadataViews.TotalSupply>():
270                return FungibleTokenMetadataViews.TotalSupply(
271                    totalSupply: NWayUtilityCoin.totalSupply
272                )
273        }
274        return nil
275    }
276
277
278	init(){ 
279		self.VaultStoragePath = /storage/NWayUtilityCoinVault
280		self.AdminStoragePath = /storage/NWayUtilityCoinAdmin
281		self.TokenBalancePublicPath = /public/NWayUtilityCoinBalance
282		self.TokenReceiverPublicPath = /public/NWayUtilityCoinReceiver
283		
284		// we're using a high value as the balance here to make it look like we've got a ton of money,
285		// just in case some contract manually checks that our balance is sufficient to pay for stuff
286		self.totalSupply = 0.0
287		let initialSupply = 999999999.0
288		let admin <- create Administrator()
289		let minter <- admin.createNewMinter(allowedAmount: initialSupply)
290		self.account.storage.save(<-admin, to: self.AdminStoragePath)
291		
292		// mint tokens
293		let tokenVault <- minter.mintTokens(amount: initialSupply)
294		self.account.storage.save(<-tokenVault, to: self.VaultStoragePath)
295		destroy minter
296		
297		let vaultCap = self.account.capabilities.storage.issue<&NWayUtilityCoin.Vault>(self.VaultStoragePath)
298        self.account.capabilities.publish(vaultCap, at: self.TokenBalancePublicPath)
299        
300        let receiverCap = self.account.capabilities.storage.issue<&NWayUtilityCoin.Vault>(self.VaultStoragePath)
301        self.account.capabilities.publish(receiverCap, at: self.TokenReceiverPublicPath)
302	}
303}