In this chapter, we're going to deploy a first version of our contracts to the test network so that we can interact with them from our web app using the Web3 library.
In your Truffle project, run the following command:
This will compile and upload the contracts to your local Ethereum network.
After the migration, you'll notice that there's a new
build folder in your Truffle project. In it, there's a
contracts folder with your contract artifacts.
These files serve as a bridge between the web app and the deployed contract that they each represent, as we'll see soon.
Calling the contract
In order to use the artifacts in our app, we need to import them somehow. Thankfully, Next allows us to import JSON files without the need for any special conversion. The only caveat in our case it that the artifact files are currently outside the Next project folder (since
build/contracts is outside of
client). Therefore, we need to copy them into the web project!
To automate this process, we will add a new script called
artifacts in our
package.json file, whose task is to copy the entire
build/contracts folder into a new one called
We'll also alter our
dev command so that it always runs
npm run artifacts before starting the server, just in case we forget to run it ourself.
Now we can import one of our artifact files, say
UserStorage.json, into our index page and log its content!
While running the app with
Now, in order to actually call one of the functions in the contract, we'll need to convert this JSON data into some kind of contract object, just like we did in the earlier chapter "Running locally". For this, theres a great little library called truffle-contract.
In our provider file, we create a new function called
getInstance. It takes the artifact's JSON data as a parameter, converts it into a contract object using truffle-contract, and returns the last deployed instance.
And we're done! This function can now be used anywhere in our web app to get an interactive version of any of our contracts. Let's try it out!
Going back to the index page file, we can now use
getInstance on our JSON and then call the contract's
profiles function to fetch the user with ID .
Refresh your browser, and you should see the following:
The reason we get an empty hex (
0x000...) for the username is obviously because there's no user with ID 1 on our network yet. But at least it seems to work!
Abstracting the user functions
Now that we have some proof that we can interact with our contracts from the web, let's abstract some of this functionality away by creating functions for the most common operations. This will help us keep the app clean and simple.
First of all, we can create a special function for what we did above – getting a user's info!
We create a new file (
client/web3/users.js) that contains a
Then we'll rewrite the code in our index page so that we instead need to click a button in order to fetch and log the user info. You can remove all the code that's in the
componentDidMount hook, as well as the imports at the top of the file.
There we go! Easy peasy!
Next, we want another function called
createUser which will call the
UserController's function with the same name.
createUser is a writable function. This means that it costs gas to execute it, and we can't just use
.call as we did with
profiles.call(). Instead, we have to pass a second parameter specifying which address we want to pay from.
In this case, we know we can get the user's MetaMask addresses using
eth.getAccounts(), so let's just select the first address that exists in that list.
Then we add a button to our index page...
After that, try clicking the button and you'll get to see the cool process of confirming a contract transaction through MetaMask!
Now that our first user is created on the network, you should be able to click the "Get user" button again and get your username in hex value!
To make it readable, we'll do just like we've done in our tests files – use the
toAscii function that's built into
Abstracting the tweet functions
While we're on a roll, let's also make some abstractions for the functions in
TweetController. That way, we can pretty much do anything from our simple button interface.
First of all, create a
tweets.js file, right next to the
users.js file in your web3 folder. This time, we'll create the
createTweet functions in one go, since we know how this stuff works already.
And, as usual, we import these functions in the page index and create some buttons for them to make them easy to test in the browser:
When it's done, click the "Create tweet" button, confirm the transaction, then click on the "Get tweet" button...
Well done, we're one step closer to having a real DApp!
In the next chapter, we will go beyond having simple buttons and look closer at how to build the web app's interface using React.