3a: A Frontend for your Smart Contract

Jeff Scott
Lamden
Published in
11 min readJun 3, 2020
Part A

This tutorial is part of a series that demonstrates how to create a working application with Python contracting.

In previous tutorials we created a Python smart contract as well as an API dev server to interact with it.

Here are the previous two tutorials in this my_token series

In this tutorial (Part 3a) we will install a frontend web framework called Sapper to create a user interface for our smart contract.

Setup

For this test we will use a simple lightweight framework called Sapper.

Dependencies

You will need the dependencies from the last two tutorials as well as these two new ones.

Install the latest NodeJs follow instructions on the NodeJs site.

Install Sapper:

With NodeJs installed; go to your my_token project directory and type this command.

npx degit "sveltejs/sapper-template#rollup" frontend
cd frontend
npm install

Now let’s test that we can view the Sapper test site.

Enter the below command from the frontend directory

npm run dev

Open your internet browser and go to http://localhost:3000

If you see this page load, then Sapper is up and running!

The Sapper starter template comes with a bunch of files we won’t need for our project and there are some files we need to create and edit.

Follow these steps to organize our project.

  1. Overwrite the files in frontend/static/ with these files

Save then to your computer then copy them to the folder

2. Delete this folder (and all files in it)

  • frontend/src/routes/blog

3. Delete these files

  • frontend/src/routes/about.svelte
  • frontend/static/successkid.jpg

4. Create this folder

  • frontend/src/routes/users

5. Create this file

  • frontend/src/routes/users/[user].svelte

5. Edit these files

  • frontend/package.json
"name": "my_token",
"description": "A simple smart contract tutorial",
  • frontend/static/manifest.json
"background_color": "#A1A0C926",
"theme_color": "#5F5E9D",
"name": "My Token",
"short_name": "My Token Tutorial Project",

6. Replace ALL the code in these files with the code provided

  • frontend/src/components/Nav.svelte
<!-- frontend/src/components/Nav.svelte --><style>
nav {
padding: 0 1rem;
display: flex;
flex-direction: row;
align-items: center;
}
h2{
margin: 0;
}
</style>

<nav>
<img alt='Token' src='token.png'>
<h2>My Token</h2>
</nav>
  • frontend/src/routes/_layout.svelte
<!-- frontend/src/routes/_layout.svelte --><script>
import Nav from '../components/Nav.svelte';
</script>

<style>
main {
position: relative;
max-width: 56em;
padding: 0 28px;
margin: 0 auto;
box-sizing: border-box;
}
</style>

<Nav />
<main>
<slot></slot>
</main>
  • frontend/src/routes/index.svelte
<!-- frontend/src/routes/index.svelte --><script></script>

<style>
*{
text-align: center;
}
</style>

<svelte:head>
<title>My Token</title>
</svelte:head>

<h1>Welcome to My Token</h1>

7. Restart the Sapper dev server

From your command prompt do a control + c to stop the dev server and then enter this command to start it again.

npm run dev

Now when you navigate your browser to http:localhost:3000 you should see our starter My Token website!

**You may need to hold shift and click refresh to get the style sheet to reapply.

The Svelte framework

Sapper is a Single Page Application (SPA) implementation of Svelte. Svelte is a web framework that makes organizing our programming logic very easy as we can keep all the JavaScript (logic), CSS (styles) and HTML (markup/layout) in one file.

Svelte allows us to create “responsive” code, which mean our webpage can easily respond and update to user interactions. By using Svelte we can get a surprising amount of functionality out of a website without using boilerplate logic (code that is native to a framework but not native to JS, CSS or HTML) or needing a Virtual DOM.

I mention this only because the files we will be editing have the extension “.svelte”; which could be different if you have made websites previously. When we build our project Svelte automatically compiles these files into the necessary .html, .js and .css files to make a fast and responsive static website.

frontend/src/routes/index.svelte

Right now, our site has a Navbar Icon and a nice greeting. What we need now is a login box and a sign-in button.

We will do this by adding a form to our index.svelte file.

Add the following code.

<!-- frontend/src/routes/index.svelte -->...
</svelte:head>

<h1>Welcome to My Token</h1>
<form>
<p>Check your token balance</p>
<input type="text" required="true"/>
<input class="button" type="submit" value="sign in" />
</form>

This will add the necessary HTML to render us

  • a message
  • an input box that the user can type in
  • a sign in button they can click.

If your refresh the website, it should now look like this now.

** Sapper will automatically refresh the webpage when you save your changes. But I mention “refreshing” just in case it fails to.

It looks great but nothing happens when we click the button! So, let’s add some interactivity.

We need our website to capture the username typed in the box, so let’s wire it up to a variable. Add the following code in bold to the input box.

<!-- frontend/src/routes/index.svelte -->...
<p>Check your token balance</p>
<input type="text" bind:value={user} required="true"/>
<input type="submit" value="sign in" />
...

This will BIND the value of the input box to a variable we called “user”.

We don’t have a user variable defined yet, so let’s add that JavaScript between our <script> tags above.

<!-- frontend/src/routes/index.svelte --><script>
let user = "";
</script>

Now our webpage can track the user input in the box. To prove it lets output the value of our user variable to the webpage.

Add this code under the h1 tag near the bottom of our file.

<!-- frontend/src/routes/index.svelte -->...
<h1>Welcome to My Token</h1>
<p>{user}</p>
<form>
...

When we use these bracket in our HTML it allows us to render JavaScript on the webpage. It’s a good way to display the value of variables our webpage is keeping track of. {user} will output the value of our user variable, which is being updated every time the user types in the box.

Refresh the webpage and type your name in the box, you should now see the webpage render what you are typing in real-time. Cool!

Okay, as cool as that is, we don’t need to display the name there. This was just to illustrate that our variable is being updated (bound) to the value of the input box.

Go ahead and remove the <p>{user}</p> line from our code we just added.

<!-- frontend/src/routes/index.svelte -->...
<h1>Welcome to My Token</h1>
<!-- Line deleted! -->
<form on:submit|preventDefault={login}>
...

When the user hits enter on the keyboard with the cursor in the input box, or clicks the button, the form will attempt a submit event. We need to bind the triggering of that event to a function that will login the user.

Add this event binding inside the form tag

<!-- frontend/src/routes/index.svelte -->...
<form on:submit|preventDefault={login}>
<p>Check your token balance</p>
<input type="text" bind:value={user} required="true"/>
...

on:submit tells Svelte we want to bind to the submit event when it’s triggered.

|preventDefault tells the webpage to ignore the default behavior of this event.

={login} tells the webpage to instead run our custom function called “login”.

Let’s now go back to our JavaScript <script> tag and write the login function.

Sapper has a built-in function that we can call to switch pages called “goto”. We need to import that function from the Sapper package and then call it in our new login function.

Add the following code in bold to our script tag.

<!-- frontend/src/routes/index.svelte --><script>
import { goto } from '@sapper/app';

let user = ""

const login = () => {
goto('/users/' + user);
}

</script>
...

This line is our import statement to make the Sapper goto function available.

import { goto } from '@sapper/app';

This is our login function definition. As you can see, we are calling the goto function and passing it the new route we want our webpage to render.

const login = () => {
goto('/users/' + user);
}

‘/users/’ + user will concatenate the string value “/users/” with the user variable we made earlier. This will create the dynamic route that Sapper will render for us. So, if the user entered the name “byron” then Sapper would attempt to take us to the route http://localhost:3000/users/byron.

Save your index.Svelte and refresh the webpage.

Enter a username and click sign in. Notice the address bar updates with our route, including the username. I’m sure you also see that the page is blank. That is because we haven’t created this route yet, but we will now.

frontend/src/routes/users/[user].svelte

For a browser to render a route it needs the html file to be served to it from the web server. In this case the browser is asking our web server at http://localhost:3000 for the html file associated with the route/users/me.

We’re good, but we could never create 1 html file for every possible username. That would take too much time. Luckily Sapper can create these html files dynamically for us and send them to the browser.

When the browser passes the route into to Sapper it will take the last part of the route and make a variable, we can access in our JavaScript. Then we can use that variable to render information about the user on the webpage.

Sounds more complicated than it is, because Sapper makes it easy.

Sapper takes the first part of the route /users/ and looks for a folder under frontend/routes that matches. In this case we created this folder during our setup in step 4.

The [user] part of our filename tells Sapper what we want the variable to be called in our file. Sapper then takes the last part of the route, me, and passes it into our file. We created this file during our setup in step 5.

This is again a regular Svelte file, but with one addition, a module declaration.

Paste this code into frontend/src/routes/users/[user].svelte. Most of it should look familiar to your from the last file, except now we have this extra <script> tag at the top that has a context=”module” property.

<!-- frontend/src/routes/users/[user].svelte --><script context="module">
export async function preload({ params, query }) {
return { user: params.user };
}
</script>

<script>
export let user;
</script>

<style>
</style>

<svelte:head>
<title>{user + "'s Tokens"}</title>
</svelte:head>

<h1>{"Hello " + user + "!"}</h1>

Refresh your page and you should now see this.

This is looking great. We changed the tab name to include the username we also included a personalized greeting.

How does this work? Well our module runs first, and the Sapper preload function within it gets passed the params object. One of the properties of this object is our “user” value. So, params.user, in the picture above would have equaled “me”. The return statement from the preload function gets passed to our regular <script> tag.

In the regular <script> tag we export a variable called user and Sapper binds that to the user value returned from the module.

Makes complete sense, right? Well, you don’t have to worry about that right now, just know it does! More importantly we can use this module to get MORE information to display on the page, including information from our Smart Contract (Remember that? the whole reason we are doing this exercise!)

Replace your current module code with this code instead.

<!-- frontend/src/routes/users/[user].svelte --><script context="module">
export async function preload({ params, query }) {
const res = await this.fetch(`http://localhost:3737/contracts/my_token/S?key=${params.user}`)
const data = await res.json();
if (data.value === 'undefined') this.error(res.status, data.message);
if (data.value === null) data.value = 0;
return { value: data.value, user: params.user };
}

</script>
...

There is a lot going on here, depending on your expertise you’ll understand all of it or none if it.

export async function preload({ params, query })

This line defines the preload function, which we talked about already.

const res = await this.fetch("http://localhost:3737/contracts/my_token/S?key=" + params.user)

On this line we call this.fetch (a wrapper around node’s fetch utility), to get the user’s token balance from our smart contracting server. The value being passed to this.fetch is our <variable> API route, created in the last tutorial; with the user concatenated to the end to become the “key”.

The response object from this.fetch will be stored in the res variable and the await command makes the code wait here for the response before continuing.

const data = await res.json();

This line gets our JSON data from the body of the response object and stores it in a variable called data so we can use it.

if (data.value !== 'undefined') this.error(res.status, data.message);

This is a check to make sure our request was successful. If we didn’t get a “value” passed back in the response, then show the error page because something is wrong.

if (data.value === null) data.value = 0;

If we did get a value, but that value was “null” then make it zero.

Our contracting server is setup to return “null” for any value not found in state.

In this case null will be returned for any user that never had tokens. If they had tokens, but transferred them all away, then they would get a value of 0 returned instead of null.

return { value: data.value, user: params.user };

Now our module is going to return TWO things,

  • user: the username from the prefetch params object
  • value: number of tokens returned from our API server.

We can use this new value variable in our <script> tag by exporting it like we did with user. We can now use it to render the Token Balance on our webpage.

  • Add the bold code below to your [user].svelte file.
<!-- frontend/src/routes/users/[user].svelte -->...
</script>

<script>
export let user;
export let value;
</script>

<style>
p{
font-size: 1.2em;
}
.shadowbox{
padding: 0.5rem 20px;
}
</style>
<svelte:head>
<title>{user + "'s Tokens"}</title>
</svelte:head>

<h1>{"Hello " + user + "!"}</h1>
<div class="shadowbox">
<p><strong>Token Balance:</strong> {value}</p>
</div>
...

Refresh the page and you should now be displaying token values.

This tutorial has run longer than I expected and ended up being more of a webpage creation tutorial than I wanted to write.

I think it’s all good information and so instead of editing it down I’m going to make this a two-parter. Part B should be out tomorrow.

You can check out the git repo for this part of the tutorial here.

>> PART 3b-A Frontend for your Smart Contract Cont.

Recap

  • Creating a website with Sapper and Svelte is easy
  • Displaying information from a smart contract via API is also easy!

I’m available to chat on twitter, telegram or linkedIn

--

--