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.
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.