Skip to content

Latest commit

 

History

History
151 lines (119 loc) · 5.5 KB

File metadata and controls

151 lines (119 loc) · 5.5 KB

Lesson 13

Important

SvelteKit is still in beta. Expect bugs! Read more here, and track progress towards 1.0 here.

This lesson was recorded before the latest breaking changes, the content is still valid but it sometimes reference a file that does not exists anymore.

Now: src/routes/index.svelte is call src/routes/+page.svelte

src/routes/__layout.svelte is call src/routes/+layout.svelte

src/routes/withdraw.svelte is now src/routes/withdraw/+page.svelte

Everything else is 100% valid. This particular content will be updated when Sveltekit reach 1.0.0 stable.

Withdraw

Now your contract can collect ETH by receiving transactions using the client application. It's time to allow you to withdraw that amount to your own account.

To accomplish this you need a way to interact with the withdraw method from the contract. To do this you'll need to add a button to call the function, let's do this by creating a new route in the application.

To create a new route you justt need to create a new folder with the name of the route you want and inside of it create a file that will hold the main logic of your route/screen/view: +page.svelte.

With the route created let's update the main layout of the application to create a navigation menu by adding two anchors that will allow you to navigate across the routes.

<!-- +layout.svelte -->
<script>
	import '../app.postcss';
</script>

<div class="w-full h-screen bg-gray-200">
	<ul class="flex flex-row pt-6 px-4 gap-12">
		<li><a href="/" class="underline text-indigo-400">Tip Jar</a></li>
		<li><a href="/withdraw" class="underline text-indigo-400">Withdraw</a></li>
	</ul>
	<div class="flex items-center flex-col p-32">
		<slot />
	</div>
</div>

Now, go back to the new withdraw route file src/routes/withdraw/+page.svelte to write the logic required to perform the withdraw call.

The logic for setup the wallet connection and communication with the contract is almost the same as beforee, so you can copy all the content of the previous route here.

...
...
+    let amItheOwner = false;
	
+	let contractBalance = null;
+	let isWithdrawing = false;

	/* Setup the contract */
	async function setupContract() {
		if (isConnected && provider) {
			contract = new ethers.Contract(contractAddress, TipJarABI.abi, provider);
+            const contractOwner = await contract.owner();
+            aItheOwner = ethers.utils.getAddress(contractOwner) === ethers.utils.getAddress(userAddress);
            
+            contract.on('NewWithdrawl', async () => {
+                contractBalance = await provider.getBalance(contractAddress);
+                balance = await provider.getBalance(userAddress);
+                isWithdrawing = false;
+			});
		}
	}

	/* Basic account setup */
	async function setup(accounts) {
		userAddress = accounts[0]; // update the state
		// Get and update the ethereum provider
		try {
			...
			...
+            contractBalance = await provider.getBalance(contractAddress); 
			...
			...
		} catch (e) {
			console.error(e);
		}
	}

+    async function withdraw() {
+        if(isConnected) {
+            isWithdrawing = true;
+            const rwContract = new ethers.Contract(contractAddress, TipJarABI.abi, provider.getSigner());
+            const tx = await rwContract.withdraw();
+            await tx.wait();
+        }   
+    }
</script>

{#if isConnected}
+    <h1 class="text-3xl text-gray-800 p-8">Withdraw from the TipJar contract</h1>
    <div class="text-sm text-gray-500 pb-4 flex flex-col gap-4">
        <p class="text-xl text-green-600">
			Successfullly connected with account: <strong>{userAddress}</strong>
		</p> 
        <ul>
            <li>Current Network: {network.name}</li>
            <li>Your current balance: {ethers.utils.formatEther(balance)} eth</li>
            +<li>Current contract balance: {ethers.utils.formatEther(contractBalance)} eth</li>
        </ul>

+        {#if amItheOwner}
+            {#if contractBalance.eq(0)}
+                <p class="text-xl text-red-600">There is no balance to withdraw</p>
+			{/if}
+            <button
+                class="bg-blue-600 text-gray-50 shadow-md rounded-md px-3 py-8 text-center disabled:opacity-25"    
+                on:click={withdraw}
+                disabled={isWithdrawing || contractBalance.eq(0)}
+            >{isWithdrawing ? '...Withdrawing' : 'Withdraw'}</button>
+        {:else}
+            <p class="text-xl text-red-600">Only the owner of the contract can withdraw the balance</p>
+        {/if}
    </div>
...
...
{:else}
	<button
		class="bg-blue-600 text-gray-50 shadow-md rounded-md px-3 py-8 text-center"
		on:click={connectWallet}>Connect with Wallet</button
	>
{/if}

The main difference against the previous route will be that:

  • You'll have a new variable named amITheOwner
  • You'll the contract owner data to compare it with the current user
  • The event listener will now listen for the NewWithdraw event.
  • You'll get and display the contract balance.
  • There will be a new withdraw function
  • The UI will contract balance.

Check if the current user is the owner and if the balance is bigger than zero, if not display a message, otherwise show the withdraw function that call the withdraw function.

Save, and check the browser.

Change the user that is connected to the app to be the owner and you can test by clicking the button.

The UI will reflect the change by setting the contract balance to zero and increasing your balance.