While it's good to know how to manually compile and run Solidity code, it gets tedious for larger apps. Thankfully, there are som great DApp frameworks that take care of this for you – the most popular one being Truffle.
Throughout the rest of the course, we'll be using Truffle to build our DApp following their best practices.
Creating a Truffle project
To install Truffle globally on your computer, run the following command:
After the installation is done, you should be able to run
truffle version to see your installed version.
Alright, now let's again re-create our HelloWorld example app from scratch (don't worry, we'll soon build something new) – this time using Truffle!
Once you've created a new folder for your project and navigated to it, the
truffle init command will automatically generate a boilerplate file structure for your DApp.
Let's go through the generated files and folders one by one so that we know what's going on!
contracts: As you could've guessed, this is where your app's Solidity contracts (
.solfiles) should go.
migrations: The files in this folder will orchestrate the deployment process, similarly to what we did in the last chapter. Thanks to Truffle however, we get a lot of functionality for free so that the files can be written in a much simpler way.
truffle-config.js: A configuration file for your project's settings.
HelloWorld in Truffle
Let's add our
HelloWorld.sol contract that we wrote earlier in the
contracts folder. Again, here's what it looks like, in case you had forgotten:
Next, as we saw in the previous chapter, we need to deploy this contract to some address in order to interact with it. With Truffle, we just add a new file to the
migrations folder to take care of this process. It should be prefixed with a
2 (so that it runs after
1_initial_migrations.js), so let's call it
Ah, isn't that nice? The whole process of compiling your contract, connecting to the network, and spending ether to deploy the bytecode is summarized in just a few lines! That certainly saves us some time!
Now, in order to deploy our contract, we need to first specify which network we want to connect to. Remember, there are several Ethereum networks out there (the real one being the "mainnet"), but in our case we simply want to connect to our own local
To specify this, we open the file
truffle-config.js and add the details of our network in JSON format, as documented on Truffle's website.
We also need to specify what version of
solc we want Truffle to use when compiling our contracts. This should match the version specified on the first pragma line of our
.sol files (in this case, ).
After this, we simply run
truffle migrate in our console (make sure that your
ganache-cli instance is still running in the background as usual so that Truffle can connect to it)!
You should now see the contract address that your contract was deployed to. In my case, the address for the
HelloWorld contract is
0xCD461e4B556eF1Aa11DB570809c0D70B7DfF0a09, but yours will obviously be something different.
Using the Truffle console
Finally, if we want to interact with our contract, we can use the Truffle console:
By entering the console, you will have the
HelloWorld contract object available as a global variable and the web3 library is automatically included and connected.
When inside the console, you can access your deployed contract instance by typing
HelloWorld.deployed(). This will return a promise, so if you want to view the result, you should use the
Using that contract instance, we can then call our
getMyName function by first saving the returned instance, and then using the syntax
We use the
.call() method whenever we call a function that does not write anything to the contract. In other words, for functions that use the
pure modifier, just like
Testing your Truffle code
As I mentioned before, testing your Solidity code is crucial. You don't want to run into a situation where funds get stolen because of a bug in your contract.
test folder, create a new file called
helloworld.js (you can name it whatever you want).
Truffle uses the Mocha testing framework behind the scenes, but uses
contract() instead of
describe() as its main function.
In our code, we'll do exactly what we did in the console: we simply fetch the deployed contract instance using
HelloWorld.deployed() and then call the
getMyName function and match it against the expected value (
Running our tests is just as simple as you'd expect:
To prove that the test is working as it should, you can try changing the expected value in your test to something else (like
Bob) and watch the test fail as you run it again:
Well done! Let's write one more test, this time for the writable
changeMyName function, so that we get the hang of it.
This time, when we call
changeMyName, we cannot use the
.call() method, since it doesn't have either the
truffle test again, and you should now see both tests passing:
We've now gone through the basics of setting up a Truffle project. In the next chapter, we will start working on a more serious application, a decentralised Twitter clone (you can see the final result here), to see what pitfalls to avoid when dealing with more advanced smart contracts.