Front-end interaction with a solidity smart contract

Jeff P
15 min readMay 20, 2021

--

I’ve wanted to do this write-up for a while now, because it’s difficult to find good (FREE) material that covers the absolute basics of how you can interact with the functions within a smart contract on a webpage.

Smart contracts ultimately boil down to two things….

Getters

You READ information stored on the smart contract. This is free….no gas required!

Setters

You WRITE information to the smart contract. This costs gas!

It’s pretty basic stuff when you break it down, yet it’s still really difficult to find some basic tutorials on creating a simple page that will allow you to interact with those getters and setters.

If you do a Google search on smart contract interaction you’ll find references to words like Ganache/Truffle/React/Web3/Ethers.js….. blah blah blah…..and the truth is that it’s off-putting for a newbie, who just wants to understand the absolute basics of Reading from a smart contract and writing to a smart contract using a web-page. I personally think if you can get to this point, then you can then start to build on that knowledge and move forward.

So I want to help people who are new to smart contracts and DApps who just want to get their head around the fundamentals first of all.

So what I want to do is first of all put together a basic smart contract that will provide some basic setters and getters, then deploy the smart contract onto a blockchain….. then finally create a web page that will allow you to interact with that smart contract.

We will deploy the contract on the HPB blockchain, because it’s fast and the gas fees are ridiculously cheap! (https://hpb.io)

Ok lets do this!

First of all I want to write a basic smart contract… If you’ve never written one before, I’d highly advise you to read through my simple tutorial on creating basic smart contracts first….go and read that, get your head around it, then come back here. I’ll wait for you ;-)

https://waxlyrical.medium.com/creating-a-smart-contract-on-the-hpb-blockchain-e676546136c1

Ok you’re back! Great!

So we’ll use the smart contract I created in the tutorial link I shared as a foundation, and add a few extra functions to it, and we can then re-deploy as a new smart contract.

Here is the code used in the previous tutorial:

pragma solidity ^0.5.7;
contract Transfer_Asset_Ownership {

address public owner;
address public contractAddress;
bytes public sha256hash;
constructor() public payable {
owner = msg.sender;
contractAddress = address(this);
}

function changeOwner(address payable _owner) public{
require(msg.sender == owner);
owner = _owner;
}

function setsha256hash(bytes memory _sha256hash) public{
sha256hash = _sha256hash;
}


}

Lets change this code a tiny bit so that you see what’s going on :-)

First we’ll change the contract name from “Transfer_Asset_Ownership” to “setters_and_getters”

Next we’ll replace the variable “bytes public sha256hash” with a new unsigned integer variable called “uint public myNewNumber”

We’ll completely change the function for “setsha256hash” to this new function:

function addNumber(uint _addThisNumber) public{
myNewNumber = _addThisNumber + myNewNumber;
}

To break this down, I’m stating that I want to provide the smart contract with a number that I will type into the page, which is represented by “_addThisNumber” and I want the smart contract to add this number to whatever the current number is stored in the variable “myNewNumber” and once those two values are added together, I want the NEW value to be assigned and stored to the variable myNewNumber.

Now because I didn’t assign any “starting value” to the variable myNewNumber, it will automatically begin with 0.

hope that makes sense.

I finally want to add one more “getter” function, which doesn’t cost gas because it’s not writing anything to the smart contract. This function will be called “addTenToMyNumber”

The function code will be as follows:

function addTenToMyNumber() public view returns (uint) {
return myNewNumber +10;
}

Very simple….whatever the number is that’s stored in the variable myNewNumber, ask the smart contract to add 10 to this value and display it. Simples!

So here is the final smart contract we will deploy:

pragma solidity ^0.5.7;
contract setters_and_getters {

address public owner;
address public contractAddress;
uint public myNewNumber;
constructor() public payable {
owner = msg.sender;
contractAddress = address(this);
}

function changeOwner(address payable _owner) public{
require(msg.sender == owner);
owner = _owner;
}

function addNumber(uint _addThisNumber) public{
myNewNumber = _addThisNumber + myNewNumber;
}
function addTenToMyNumber() public view returns (uint) {
return myNewNumber +10;
}


}

Ok, so the smart contract has the following “getters” which are public variables, which can be viewed, which in this case are:

  • The address of the “owner”
  • The address of the contract itself (“contractAddress”)
  • The value of “myNewNumber” that is set on the contract
  • Finally, the function call of addTenToMyNumber() which will return a value of myNewNumber plus 10.

The contract also has the “setter” which is the function to actually add a number to the smart contract. This is effectively, the number you submit plus whatever is already stored in the variable “myNewNumber”. Read through the contract to get an understanding of what it’s doing before you move forwards.

Right, let’s deploy this to the HPB blockchain…. go back to the tutorial link I shared if you don’t know how to do this, but you are basically deploying with https://remix.hpb.io

(Remember, you’ll need Metamask browser extension installed and pointing to the HPB network — It’s in the previous tutorial)

Once deployed, you can see your “setters” and “getters” in the run tab on remix here:

So the red buttons are “setters” (cost gas) and the blue buttons are “getters” (free)

Try interacting with the contract you’ve deployed within the remix environment.

Ok so you can see that you are interacting with a live smart contract on the blockchain, using buttons on a webpage…..this in its most basic form is like a DApp! Interaction using a webpage!

So now what we want to do is create our own webpage to interact with this smart contract, not use Remixes buttons! We want our own buttons!

Before we create a webpage that runs on the internet, lets create a page on our home PC….that way we can see if it’s working as we expect. Once we’re confident that the web page works, we can deploy it on the internet and try it out :-)

Let’s first create a “framework” of pages and folders that we’re going to need.

first thing you’ll need to do is install Node.js on your PC

You will also find life easier if you install a “code editor” — I recommend Atom:

Once that’s all installed, open up a command prompt (CMD) on your computer and make a new directory. In Windows 10, the command to do this md [yournewfoldername] and then use the command cd [yournewfoldername] to switch into the folder:

once you’re in this folder, we want to install some dependencies…

The first thing we want to do is get the react framework to create the files and folders structure for our pages. Do do this we use “npx create-react-app [folder name]”

(Pay special attention to the fact that I used npx and not npm….this catches people out! — npm is a node installer…… npx is a node executor….. we want react to create an app structure for us and generate a folder, so we use npx!)

For this example I will use “npx create-react-app@latest mydapp — use-npm

Next, we want to install web3 which is the clever node module that allows web pages to actually connect to smart contract on the blockchain and allows you to pay the gas fee to write to them using Metamask.

the first thing we want to do is switch to the “mydapp” folder that create-react-app just created for us, and then install web3.

cd mydapp

We then use “npm install web3” to do this

Once this is done, we can now switch to our atom editor (or whatever your text editor of choice happens to be) and get started.

When you open the folder “mydapp” it will look like this:

We can verify that the web3 module installed correctly by looking inside the “node modules” folder

Ok so we have the folder structure that we need.

Let’s first of all setup our local instance to get react running in a browser.

Go back to your command window, and type in “npm run start” which will start up react in a browser window.

If the browser doesn’t launch automatically, then open up a window, and go to “localhost:3000” and you should see this.

It has a cool blue spinning logo!

So what are you actually looking at here? Well you’re actually looking at a rendered page, and the page is from the file App.js in the src folder.

We can verify this by changing the text in the js file…. lets change the line 10 that says:

Edit <code>src/App.js</code> and save to reload.

We’ll erase that line completely and replace it with:

This is kinda cool! 

then save the file in your text editor, and now head back to the localhost web page.

Ok before we move on, we need to introduce web3. We have installed the node module of web3, but we still need to reference this module to allow for interactivity with our smart contracts, so let’s do that first. Create a new file in the src folder called web3.js

Now let’s import an instance of web3 into this new file. Use the following code:

import Web3 from "web3";

window.ethereum.request({ method: "eth_requestAccounts" });

const web3 = new Web3(window.ethereum);

export default web3;

remember to save!

The next thing we want to do is import this newly-created web3.js file into our App.js file so that we can reference it, so switch back to the App.js file and add in the following line of code to import:

import web3 from './web3';

Ok so we’ve now setup the ability for web3 to interact with this App.js page.

The next thing we want to do is reference the ABI code and the actual contract address of the smart contract we deployed. We can get this information from https://remix.hpb.io

Before we do this, let’s create another file in the src folder, and call it myContract.js

Inside this file, we will put in the following code:

import web3 from './web3';const address = '';const abi =  ;

Now the values for address and abi are currently empty, so we need to fill them out. Let’s head back to https://remix.hpb.io to get them.

In the run tab, you can copy the deployed contract address by clicking on the icon I’ve indicated here:

Paste this address between the two quotes for the address:

Next we need the ABI code…. head to the compile tab and click on the ABI button to copy that.

Now paste the ABI code into the space between the = sign and the semi-colon:

if you did this correctly, the bottom of the page will show the ABI ending with ];

The final thing we want to do at the very bottom of the page is export this for our App.js file.

We add the following line of code at the very bottom of the page:

export default new web3.eth.Contract(abi, address);

Now we can go back to App.js and reference this file.

import myContract from './myContract';

Ok lets now look to start rendering some web3 information to our page….

Immediately after the last import statement, we also want to import in React to use various react components, such as “componentDidMount()” and “render()”:

You can find out more about React components here if you wish to dive deeper:

https://reactjs.org/docs/react-component.html

We add in the following import statement:

import React from "react";

Right…. let’s start rendering some information from the smart contract!

We’ll begin with the “owner” variable. This was a public address “getter” on the smart contract, and is basically the wallet address of the person who deployed the smart contract (You!)

Let’s add in the following lines of code immediately after the last import statement:

class App extends React.Component {state = {
owner: ''
};
async componentDidMount() {
const owner = await myContract.methods.owner().call();
this.setState({owner});
}
render(){

So we’ve created a class and called it “App” and will be using the React Component.

First of all we want to set an empty state for the owner variable

owner: ''

we then want to use the React component “componentDidMount()” to create a constant for obtaining the owner address…..so we name the constant “owner” and then we are referencing (basically calling) the “owner()” function within the smart contract ABI code that sits inside the myContract.js file we created.

Once we do that, we then want to set that state of our “owner” constant.

Finally, we want to render that information.

Ok, the next thing we want to do is remove the following line as it’s not needed:

function App() {

Now because everything will sit inside the React App class we added, we need to close out the code with another closing curly brace at the bottom:

The last thing we need to do, is simply decide where we want that “owner” address information to actually appear on the rendered page.

Let’s replace the line we added earlier that said “This is kinda cool!” with our rendered information.

Replace that line with the following:

The owner address is:  {this.state.owner}

Head back to the webpage, and if all went well, you should see something like this :-)

Give yourself a pat on the back because you’ve just rendered your first “getter” from the smart contract on the blockchain!

Let’s add the rest of the “getters” from the smart contract

  • contractAddress
  • myNumber
  • addTenToMyNumber

Ok so we first of all declare them inside the state:

state = {
owner: '',
contractAddress: '',
myNewNumber: '',
addTenToMyNumber: ''
};

we also add them as constants, and also include them inside the curly braces of this.setState:

async componentDidMount() {
const owner = await myContract.methods.owner().call();
const contractAddress = await myContract.methods.contractAddress().call();
const myNewNumber = await myContract.methods.myNewNumber().call();
const addTenToMyNumber = await myContract.methods.addTenToMyNumber().call();
this.setState({owner, contractAddress, myNewNumber, addTenToMyNumber});


}

and finally, we add them to where we want them to be the page:

        <p>
The owner address is: {this.state.owner}
</p>
<p>
The contract address is: {this.state.contractAddress}
</p>
<p>
The stored number is: {this.state.myNewNumber}
</p>
<p>
Adding 10 to my number equals: {this.state.addTenToMyNumber}
</p>

Heading back to the webpage, if all went well, you should see something that looks like this:

Hopefully you’ve got the concept of rendering “getters” locked down now….. let’s finish this off with a “setter” and allow us to write a new number to the smart contract :-)

In order to achieve this we’re going to need three things…. a form field to type a number into, an actual button to click, and an “event handler” so that the page knows what to do when the button is clicked. Lets add the form field and the button into the page first:

Let’s put it just before where the page shows the stored number…so we’ll make some space in the middle:

We’ll add in the following code for the button and form field:

<form>
<div>
<label>Type in the number you want to add:</label>
<input
value={this.state.value}
onChange={event => this.setState({ value: event.target.value })}
/>
</div>
<button>click to confirm</button>
</form>

Should now look like this:

Ok, save the page and head over to the webpage. If all went well, you should see something like this:

The final thing we need to do is add in an “event handler” to that the page knows what to do when we click on the button to submit.

First lets create the onSubmit function by adding in the following lines of code after the componentDidMount section:

onSubmit = async(event) => {
event.preventDefault();
this.setState({ message: 'Waiting on transaction success...'});const accounts = await web3.eth.getAccounts();
await myContract.methods.addNumber(this.state.value).send({
from: accounts[0]
});
this.setState({ message: 'You have submitted your number!'});};

We just need to attach this function to the form now, so we make a slight adjustment adjust to the opening form tag…

<form onSubmit={this.onSubmit}>

We’re done with the code! Your final code should look like this:

import logo from './logo.svg';
import './App.css';
import web3 from './web3';
import myContract from './myContract';
import React from "react";
class App extends React.Component {state = {
owner: '',
contractAddress: '',
myNewNumber: '',
addTenToMyNumber: ''
};async componentDidMount() {
const owner = await myContract.methods.owner().call();
const contractAddress = await myContract.methods.contractAddress().call();
const myNewNumber = await myContract.methods.myNewNumber().call();
const addTenToMyNumber = await myContract.methods.addTenToMyNumber().call();
this.setState({owner, contractAddress, myNewNumber, addTenToMyNumber});}onSubmit = async(event) => {
event.preventDefault();
this.setState({ message: 'Waiting on transaction success...'});const accounts = await web3.eth.getAccounts();
await myContract.methods.addNumber(this.state.value).send({
from: accounts[0]
});
this.setState({ message: 'You have submitted your number!'});};render(){return (
<div className="App">
<header className="App-header">
<img src={logo} className="App-logo" alt="logo" />
<p>
The owner address is: {this.state.owner}
</p>
<p>
The contract address is: {this.state.contractAddress}
</p>
<form onSubmit={this.onSubmit}>
<div>
<label>Type in the number you want to add:</label>
<input
value={this.state.value}
onChange={event => this.setState({ value: event.target.value })}
/>
</div>
<button>click to confirm</button>
</form>
<p>
The stored number is: {this.state.myNewNumber}
</p>
<p>
Adding 10 to my number equals: {this.state.addTenToMyNumber}
</p>
<a
className="App-link"
href="https://reactjs.org"
target="_blank"
rel="noopener noreferrer"
>
Learn React
</a>
</header>
</div>
);
}
}
export default App;

Let’s try it out! I’ll add a number into the form and then click the button.

this is how it looks first of all…

I submit my number….

and refresh the page…..

And there we have it…. basic smart contract interaction with a web page.

In the next tutorial, we’ll improve on this by introducing next.js which allows for server side rendering, which means those values would refresh on the page without me having to hit F5 on my keyboard to refresh the page.

We’ll also add some CSS and styling to make the look and feel of the page appear different

Finally, we’ll deploy to the internet on a real webpage using Netlify.

--

--

Jeff P
Jeff P

Written by Jeff P

I tend to write about anything I find interesting. There’s not much more to it than that really :-)