Smart Contract

Sushi

A.de7a5daf9df48c65.Sushi

Deployed

16h ago
Feb 28, 2026, 02:29:24 AM UTC

Dependents

0 imports
1import FungibleToken from 0xf233dcee88fe0abe
2
3// Token contract of Sushi (SUSHI)
4access(all) contract Sushi: FungibleToken { 
5
6	// -----------------------------------------------------------------------
7	// Entitlements
8	// -----------------------------------------------------------------------
9	access(all) entitlement AdminOwner
10	access(all) entitlement MinterProxyOwner
11	
12	// -----------------------------------------------------------------------
13	// Sushi contract Events
14	// -----------------------------------------------------------------------
15	
16	// Event that is emitted when the contract is created
17	access(all) event TokensInitialized(initialSupply: UFix64)
18	
19	// Event that is emitted when tokens are withdrawn from a Vault
20	access(all) event TokensWithdrawn(amount: UFix64, from: Address?)
21	
22	// Event that is emitted when tokens are deposited to a Vault
23	access(all) event TokensDeposited(amount: UFix64, to: Address?)
24	
25	// Event that is emitted when new tokens are minted
26	access(all) event TokensMinted(amount: UFix64)
27	
28	// Event that is emitted when tokens are destroyed
29	access(all) event TokensBurned(amount: UFix64)
30	
31	// Event that is emitted when a new minter resource is created
32	access(all) event MinterCreated()
33	
34	// Event that is emitted when a new burner resource is created
35	access(all) event BurnerCreated()
36	
37	// Event that is emitted when a new MinterProxy resource is created
38	access(all) event MinterProxyCreated()
39	
40	// -----------------------------------------------------------------------
41	// Sushi contract Named Paths
42	// -----------------------------------------------------------------------
43	// Defines Sushi vault storage path
44	access(all) let VaultStoragePath: StoragePath
45	
46	// Defines Sushi vault public balance path
47	access(all) let BalancePublicPath: PublicPath
48	
49	// Defines Sushi vault public receiver path
50	access(all) let ReceiverPublicPath: PublicPath
51	
52	// Defines Sushi admin storage path
53	access(all) let AdminStoragePath: StoragePath
54	
55	// Defines Sushi minter storage path
56	access(all) let MinterStoragePath: StoragePath
57	
58	// Defines Sushi minters' MinterProxy storage path
59	access(all) let MinterProxyStoragePath: StoragePath
60	
61	// Defines Sushi minters' MinterProxy capability public path
62	access(all) let MinterProxyPublicPath: PublicPath
63	
64	// -----------------------------------------------------------------------
65	// Sushi contract fields
66	// These contain actual values that are stored in the smart contract
67	// -----------------------------------------------------------------------
68	// Total supply of Sushi in existence
69	access(all) var totalSupply: UFix64
70	
71	// Vault
72	//
73	// Each user stores an instance of only the Vault in their storage
74	// The functions in the Vault are governed by the pre and post conditions
75	// in FungibleToken when they are called.
76	// The checks happen at runtime whenever a function is called.
77	//
78	// Resources can only be created in the context of the contract that they
79	// are defined in, so there is no way for a malicious user to create Vaults
80	// out of thin air. A special Minter resource needs to be defined to mint
81	// new tokens.
82	//
83	access(all) resource Vault: FungibleToken.Vault, FungibleToken.Provider, FungibleToken.Receiver, FungibleToken.Balance { 
84		
85		// holds the balance of a users tokens
86		access(all) var balance: UFix64
87		
88		// initialize the balance at resource creation time
89		init(balance: UFix64) { 
90			self.balance = balance
91		}
92		
93		// withdraw
94		//
95		// Function that takes an integer amount as an argument
96		// and withdraws that amount from the Vault.
97		// It creates a new temporary Vault that is used to hold
98		// the money that is being transferred. It returns the newly
99		// created Vault to the context that called so it can be deposited
100		// elsewhere.
101		//
102		access(FungibleToken.Withdraw) fun withdraw(amount: UFix64): @{FungibleToken.Vault} { 
103			self.balance = self.balance - amount
104			emit TokensWithdrawn(amount: amount, from: self.owner?.address)
105			return <-create Vault(balance: amount)
106		}
107		
108		// deposit
109		//
110		// Function that takes a Vault object as an argument and adds
111		// its balance to the balance of the owners Vault.
112		// It is allowed to destroy the sent Vault because the Vault
113		// was a temporary holder of the tokens. The Vault's balance has
114		// been consumed and therefore can be destroyed.
115		access(all) fun deposit(from: @{FungibleToken.Vault}): Void { 
116			let vault <- from as! @Sushi.Vault
117			self.balance = self.balance + vault.balance
118			emit TokensDeposited(amount: vault.balance, to: self.owner?.address)
119			vault.balance = 0.0
120			destroy vault
121		}
122		
123		access(all) fun createEmptyVault(): @{FungibleToken.Vault} { 
124			return <-create Vault(balance: 0.0)
125		}
126		
127		access(all) view fun isAvailableToWithdraw(amount: UFix64): Bool { 
128			return self.balance >= amount
129		}
130
131		access(all) view fun getViews(): [Type] {
132            return Sushi.getContractViews(resourceType: nil)
133        }
134
135        access(all) fun resolveView(_ view: Type): AnyStruct? {
136            return Sushi.resolveContractView(resourceType: nil, viewType: view)
137        }
138	}
139	
140	// createEmptyVault
141	//
142	// Function that creates a new Vault with a balance of zero
143	// and returns it to the calling context. A user must call this function
144	// and store the returned Vault in their storage in order to allow their
145	// account to be able to receive deposits of this token type.
146	//
147	access(all) fun createEmptyVault(vaultType: Type): @{FungibleToken.Vault} { 
148		return <-create Vault(balance: 0.0)
149	}
150	
151	// Administrator
152	//
153	// Resource object that token admin accounts can hold to create new minters and burners.
154	//
155	access(all) resource Administrator { 
156		// createNewMinter
157		//
158		// Function that creates and returns a new minter resource
159		//
160		access(AdminOwner) fun createNewMinter(): @Minter { 
161			emit MinterCreated()
162			return <-create Minter()
163		}
164		
165		// createNewBurner
166		//
167		// Function that creates and returns a new burner resource
168		//
169		access(AdminOwner) fun createNewBurner(): @Burner { 
170			emit BurnerCreated()
171			return <-create Burner()
172		}
173	}
174	
175	// Minter
176	//
177	// Resource object that token admin accounts can hold to mint new tokens.
178	//
179	access(all) resource Minter { 
180		
181		// mintTokens
182		//
183		// Function that mints new tokens, adds them to the total supply,
184		// and returns them to the calling context.
185		//
186		access(all) fun mintTokens(amount: UFix64): @Sushi.Vault { 
187			pre{ 
188				amount > 0.0:
189					"Amount minted must be greater than zero"
190			}
191			Sushi.totalSupply = Sushi.totalSupply + amount
192			emit TokensMinted(amount: amount)
193			return <-create Vault(balance: amount)
194		}
195	}
196	
197	// Burner
198	//
199	// Resource object that token admin accounts can hold to burn tokens.
200	//
201	access(all) resource Burner { 
202		
203		// burnTokens
204		//
205		// Function that destroys a Vault instance, effectively burning the tokens.
206		//
207		// Note: the burned tokens are automatically subtracted from the 
208		// total supply in the Vault destructor.
209		//
210		access(all) fun burnTokens(from: @{FungibleToken.Vault}) { 
211			let vault <- from as! @Sushi.Vault
212			let amount = vault.balance
213			destroy vault
214			emit TokensBurned(amount: amount)
215		}
216	}
217	
218	access(all) resource interface MinterProxyPublic { 
219		access(all) fun setMinterCapability(cap: Capability<&Sushi.Minter>): Void
220	}
221	
222	// MinterProxy
223	//
224	// Resource object holding a capability that can be used to mint new tokens.
225	// The resource that this capability represents can be deleted by the admin
226	// in order to unilaterally revoke minting capability if needed.
227	access(all) resource MinterProxy: MinterProxyPublic { 
228		
229		// access(self) so nobody else can copy the capability and use it.
230		access(self) var minterCapability: Capability<&Minter>?
231		
232		// Anyone can call this, but only the admin can create Minter capabilities,
233		// so the type system constrains this to being called by the admin.
234		access(all) fun setMinterCapability(cap: Capability<&Minter>) { 
235			self.minterCapability = cap
236		}
237		
238		access(MinterProxyOwner) fun mintTokens(amount: UFix64): @Sushi.Vault { 
239			return <-((self.minterCapability!).borrow()!).mintTokens(amount: amount)
240		}
241		
242		init(){ 
243			self.minterCapability = nil
244		}
245	}
246	
247	// createMinterProxy
248	//
249	// Function that creates a MinterProxy.
250	// Anyone can call this, but the MinterProxy cannot mint without a Minter capability,
251	// and only the admin can provide that.
252	//
253	access(all) fun createMinterProxy(): @MinterProxy { 
254		emit MinterProxyCreated()
255		return <-create MinterProxy()
256	}
257
258	// -----------------------------------------------------------------------
259	// MetadataViews - Purposely Empty
260	// -----------------------------------------------------------------------
261    access(all) fun resolveContractView(resourceType: Type?, viewType: Type): AnyStruct? {
262        return nil
263    }
264
265    access(all) view fun getContractViews(resourceType: Type?): [Type] {
266        return []
267    }
268	
269	init(){ 
270		self.VaultStoragePath = /storage/basicBeastsSushiVault
271		self.ReceiverPublicPath = /public/basicBeastsSushiReceiver
272		self.BalancePublicPath = /public/basicBeastsSushiBalance
273		self.AdminStoragePath = /storage/basicBeastsSushiAdmin
274		self.MinterStoragePath = /storage/basicBeastsSushiMinter
275		self.MinterProxyPublicPath = /public/basicBeastsSushiMinterProxy
276		self.MinterProxyStoragePath = /storage/basicBeastsSushiMinterProxy
277		self.totalSupply = 0.0
278		
279		// Create the Vault with the total supply of tokens and save it in storage
280		let vault <- create Vault(balance: self.totalSupply)
281		self.account.storage.save(<-vault, to: self.VaultStoragePath)
282		
283		// Create a public capability to the stored Vault that only exposes
284		// the `deposit` method through the `Receiver` interface
285		var capability_1 = self.account.capabilities.storage.issue<&Sushi.Vault>(self.VaultStoragePath)
286		self.account.capabilities.publish(capability_1, at: self.ReceiverPublicPath)
287		
288		// Create a public capability to the stored Vault that only exposes
289		// the `balance` field through the `Balance` interface
290		var capability_2 = self.account.capabilities.storage.issue<&Sushi.Vault>(self.VaultStoragePath)
291		self.account.capabilities.publish(capability_2, at: self.BalancePublicPath)
292		let admin <- create Administrator()
293		self.account.storage.save(<-admin, to: self.AdminStoragePath)
294		
295		// Emit an event that shows that the contract was initialized
296		emit TokensInitialized(initialSupply: self.totalSupply)
297	}
298}
299