04 - Introduction to Truffle Suite

Introduction to Truffle Suite

Before we go into the Solidity section, we want to make sure you have a place where you can play around with the Solidity code you’re starting to learn. Enter the Truffle Suite!

Truffle is an excellent tool to learn Solidity development but, as we’ll show later in the course, it’s also got advanced features. Don’t be deceived by how easy it is!

History and Evolution

As with any emergent ecosystem, tooling in the early days of EVM-based dapp development was somewhat primitive. Developers were required to install and utilize multiple, disjointed tools and services making for a complex workflow with a steep learning curve.

Things have come a long way since then, with tools and services like Codefi, Infura, Metamask, and OpenZeppelin Contracts that simplify a significant number of smart contract software development lifecycle stages.

Despite these advancements, there are still numerous pitfalls, particularly related to the security of your contracts, which makes web3 development different to what you might be used to when building against a more centralized paradigms.

Why Truffle Suite?

The Truffle Suite was built to streamline the smart contract development process. Out of the box it includes a large, and growing, collection of commands that you can execute as you write, troubleshoot, and maintain your smart contracts.

A good example of this is contract compilation (wherein you convert your high-level contract code to something that can be natively understood by an Ethereum-node). As part of this feature, Truffle can also intelligently download the necessary compiler version(s) and even enable you to write your contracts in different language versions.

Additional reasons why developers might use Truffle to build their dapps include the following…

  • Built-in support for compiling, deploying and linking your contract
  • An automated contract testing framework built on Mocha and Chai
  • A built-in console that allows you to directly interact with your compiled contracts

This is just scratching the surface; as you’ll see when we dive-in, the Truffle Suite and the broader tooling ecosystem makes your life as a dapp developer both productive and fun!

Installation

The following walks you through installation of both Truffle CLI and Ganache.

Truffle CLI

The Truffle Suite requires the following…

  • Node.js v8.9.4 or later
  • NPM v5.0.3 or later
  • Windows, Linux or Mac OS X

Truffle also requires that you have a running Ethereum client which supports the standard JSON RPC API (which is nearly all of them). While there are many clients, the Truffle Suite also ships with Ganache, essentially a one-click EVM-based blockchain node for local testing.

Once you have the proper Node and npm installed, please run the following command from your terminal to install Truffle:

$ npm install -g truffle

Once successful, this will allow you to run Truffle from your command line anywhere on your machine.

Note: In case you run into errors due to write permission on your local machine, try to run the command preceded by sudo:

$ sudo npm install -g truffle

Ganache

Ganache has the same requirements as Truffle (as specified above). In addition, it also comes in two flavors, both a standalone CLI for more intermediate-advanced users and a UI version which is great for users that are just starting out. It’s worth noting that a version of Ganache also ships directly with Truffle which can be instantiated with the truffle develop command.

Ganache CLI can be installed via the following:

$ npm install -g ganache-cli 

Note: In case you run into errors due to write permission on your local machine, try to run the command preceded by sudo:

$ sudo npm install -g ganache-cli

Ganache UI is available as download here. You can also install the latest beta (at the time of writing) that includes Filecoin support here.

Congratulations! You’ve just successfully installed Truffle and Ganache and are ready to get started developing.

Introducing the Truffle Suite

Now that we have Truffle (and optionally a standalone Ganache version) installed we’re nearly ready to begin diving in and writing our first smart contract. We’d like to cover a few more things before diving in.

Network Support

As we discussed previously in the course, we are living in an increasingly multi-chain world. There multiple popular public blockchain networks and Truffle Suite aims to serve as many of these as is realistic.

At the time of writing, Truffle Suite supports development on the following networks:

  • Ethereum
  • Quorum
  • Hyperledger Fabric
  • Corda
  • Filecoin
  • Tezos
  • Polygon
  • Arbritrum
  • Optimism PBC

That said, Truffle’s richest support is for that of EVM (Ethereum Virtual Machine) based blockchains. This is in part due to Truffle’s lineage and the fact that supporting every blockchain would be futile, particularly given the rapid evolution of the space.

Given the above, the bulk of this section of the course will be specifically focused on EVM based chains (unless specified otherwise).

Language Support

As highlighted earlier, amongst many other things, Truffle handles the compilation of your contracts from that of a higher-level language to Ethereum bytecode, which is the language “spoken” by the nodes on the network.

Out of the box, Truffle supports the following:

  • Solidity
  • Vyper
  • Yul (experimental and not for beginners)

At the time of writing, Solidity is by far the most popular language for writing smart contracts, and as with everything in the space, things have been moving rapidly and have now witnessed some major projects built using Vyper.

Core Truffle Commands

Truffle is built around a large collection of commands that are used as a part of the contract development workflow. Examples of these include:

  • truffle init
  • truffle compile
  • truffle test
  • truffle debug
  • truffle migrate

Note that you can see a complete list of the available commands by running truffle help.

As you can likely infer from the commands, they map to key stages of the development lifecycle. More on this in the upcoming section!

Truffle Boxes

Up until now we’ve been writing all the code, scripts, and config ourselves and while this follows the mantra of “learning by doing”, there’s another great resource at your disposal and that is Truffle boxes.

Learning with Truffle boxes

As per the description, boxes are “helpful boilerplates” that comprise of sample contracts, front-end code (using a variety of different frameworks), and applied boxes that focus on a particular theme or protocol such as L2. From a learning standpoint they’re a useful to way to augment your learning by immediately getting hands-on.

At the time of writing, here are some good boxes:

Installing a box is simply a case of using the unbox command, for example:

$ truffle unbox optimism

Beyond this, simply follow along with the optimism box readme.

We’ll discuss boxes more when we dive deeper into developer tooling and more advanced Truffle, but feel free to explore available boxes. Two popular boxes for folks new to Truffle are Petshop and Metacoin.

In the next section, we’ll take a simple smart contract and use it to explore the initial commands for developing using Truffle.

# Truffle Suite Deep Dive

As with most things, the best way to learn is by doing, so without further ado let’s dive into a hands on example of using Truffle.

In this example we’ll be leveraging some of the core Truffle commands to build the decentralized equivalent of a “Hello World!” program, “SimpleStorage”. As the name suggests, this example will provide a means of both storing some on-chain data (essentially state stored indefinitely on the blockchain) and subsequently retrieving this state.

Note: If you’re going to be following along, this example assumes you followed the steps last lesson to successfully install Truffle

Initialize an Empty Project

Let’s begin by creating an empty project using the init command. In a new directory (e.g. “SimpleStorage”) and from your terminal, run the following command.

$ truffle init

Assuming everything worked successfully you should see the following output and a number of directories (contracts, migrations, etc) created in the current directory.

Starting init...
 ================ 
> Copying project files to /Users/bluer/Developer/temp

 Init successful, sweet! 

Try our scaffold commands to get started: 
$ truffle create contract YourContractName # scaffold a contract 
$ truffle create test YourTestName # scaffold a test 

http://trufflesuite.com/docs

Congratulations, you now have a bare bones project! Next up, let’s create a contract within which we’ll be able to store our SimpleStorage project’s code.

Create a Contract

Truffle provides a create command with which you can achieve this, although as we’ll show later it’s often just as easy to create the file via your favorite editor environment.

$ truffle create contract SimpleStorage

This will create a new Solidity (note that this is the default language) file, SimpleStorage.sol within your contracts directory.

Using a code editor, or using something like nano from the command line, paste the following Solidity code into the SimpleStorage.sol file and save:

// SPDX-License-Identifier: MIT 

pragma solidity >=0.4.21 <0.7.0; 
contract SimpleStorage { 
    uint storedData; 
    function set(uint x) public { 
        storedData = x; 
    } 

   function get() public view returns (uint) {
       return storedData; 
   } 
}

Sweet, your first contract! Now let’s try out the compile command we saw earlier.

Compilation, baby!

Running the compile command from your terminal like the following:

$ truffle compile Compiling your contracts... 
===========================
 > Compiling ./contracts/Migrations.sol 
> Compiling ./contracts/SimpleStorage.sol 
> Artifacts written to /Users/bluer/Developer/temp/build/contracts 
> Compiled successfully using:
    - solc: 0.5.16+commit.9c3226ce.Emscripten.clang

Assuming all went smoothly, Truffle should have compiled your contract and added the resultant output (something referred to as build artifacts that we’ll explore in more detail later) to build/contracts/SimpleStorage.json.

Note that you’ll also likely see some references to Migrations. This is a mechanism used by Truffle to store the details related to the last migration (deployment) on-chain.

Next up we’re going to explore deploying our contract to a simulation of a blockchain network using Ganache.

Migrating (or Deploying) Your Contract

So we’ve created and compiled a contract, but now we need somewhere to deploy it so we can begin testing. This is where Ganache comes in!

As alluded to earlier, Ganache comes in a number of different flavors. For ease we’re going to start by using the version built directly into Truffle itself (more on standalone Ganache CLI and Ganache UI shortly).

To achieve this we can use Truffle’s develop command which both starts up a Ganache instance and provides us with an interactive REPL with which we can actually interact with our contracts.

$ truffle develop

And you should see this, if successful:

Truffle Develop started at http://127.0.0.1:9545/ 

Accounts: (0) 0x5ca1605d4671669b38f7e37c881ed996ede5ac68 … 
Private Keys: (0) dd7a8c358901b0f572e461585c9ab27f92b24902c45859114776af12077cb208 …

 Mnemonic: cloth either reunion project inflict inside ghost welcome tip lemon again knee 

⚠️ Important ⚠️ : This mnemonic was created for you by Truffle. It is not secure. 
Ensure you do not use it on production blockchains, or else you risk losing funds. 

truffle(develop)>

We’ll be glossing over the details of the above output for the moment, other than to say it gives us access to 10 pre-funded accounts (as a default) that we can leverage as a means of interacting contracts.

Before we actually migrate our contract we’ll need to create a migration script. This step enables you to granularly instruct Truffle how to migrate your contracts, including things like constructor arguments.

In the migrations directory create a file called 2_deploy_contracts.js and copy into that file the following:

var SimpleStorage = artifacts.require("./SimpleStorage.sol"); module.exports = function(deployer) { deployer.deploy(SimpleStorage); };

The numerical prefix of 2_deploy_contracts.js is actually important for two reasons. First, it dictates the order in which scripts are executed. Second, it’s the index stored on-chain by the Migration.sol to keep track of successful migrations per its last_completed_migration value.

Now that we have a migration script ready to go we can migrate as follows. Since we’re doing this migration from the Truffle console we started with truffle develop, you can actually omit truffle from your command and just run:

$ truffle(develop)> migrate

Assuming all goes well, you should see the following:

2_deploy_contracts.js ====== Deploying ‘SimpleStorage’ ------------------------- > transaction hash: 0x172f0cff41ea21a7dbbb52883a7499306f54277120fa89bbc6621c7b7efccb80 > Blocks: 0 Seconds: 0 > contract address: 0x524B2860a2489E385C5e12537f58d5a09A9d33ab > Saving migration to chain. > Saving artifacts ------------------------------------- > Total cost: 0.000192354 ETH Summary ======= > Total deployments: 2 > Final cost: 0.000767772 ETH - Blocks: 0 Seconds: 0 - Saving migration to chain. - Blocks: 0 Seconds: 0 - Saving migration to chain.

One of the key output values from the above is the contract address (0x524B2860a2489E385C5e12537f58d5a09A9d33ab in the above example). As the name might suggest, this is the address of the deployed instance of contract and the means with how you’d reference it when sending future transactions.

Migrations is definitely more of a deeper topic that we’ll be covering more later. In the interim, more details on migrations can be found in Truffle’s documentation here.

Interacting with SimpleStorage

Last but not least, let’s go ahead and actually interact with our freshly deployed SimpleStorage contract.

Ultimately, there’s a number of ways in which you can interact with on-chain contracts, but for the sake of ease in this instance we’ll be doing it directly from the Truffle console.

Let’s create an instance of our deployed contract via the following. Note that behind the scenes, Truffle is referencing the build artifacts (which in turn store the aforementioned contract address), that’s why this is an async JavaScript call.

$ truffle(develop)> let storage = await SimpleStorage.deployed()

You can now interact via the returned storage object, for example. Let’s do that now, but calling the set contract method, writing a new value in the contract state. As you’ll see, given this invocation results in a change of on-chain state, we actually get a transaction “receipt” returned.

$ truffle(develop)> storage.set(42) { tx: ‘0x46e4bb35108e5ecf7ff656008295fda572a753476d5e04c286fcdb7868447dd6’, receipt: { transactionHash: ‘0x46e4bb35108e5ecf7ff656008295fda572a753476d5e04c286fcdb7868447dd6’, transactionIndex: 0, blockHash: ‘0x85dbdf5d71194cb0d841d58bbac283ccf078ce0ebe1c054c6c2ab76442459894’, blockNumber: 9, from: ‘0x5ca1605d4671669b38f7e37c881ed996ede5ac68’, to: ‘0x524b2860a2489e385c5e12537f58d5a09a9d33ab’, … }

And a drum roll for this last command! Run the following to get the originally stored number. (We can also explain the syntax a little bit, since it’s a bit odd: We’re creating a promise to deliver a big number, which will be our stored number.)

$ truffle(develop)> (await storage.get()).toNumber() 42

Congratulations! You’ve now just created, deployed, and interacted with your very first smart contract using the Truffle Suite. Next, we’re going to walkthrough how to use Ganache GUI.

Ganache GUI

Ganache UI can be really helpful for folks new to smart contract development. Due to its visual nature, it’s a great way to familiarize yourself with all the core constructs of an EVM-based blockchain and help move past that stage of “not knowing what you don’t know”. It’s fully cross-platform and available to download here.

image of ganache GUI

As you can seen in the above screenshot, it has tabs for all the major constructs including accounts, blocks, transactions, contracts, and events. It also starts it’s own chain instance on port 7545 (note that by default truffle develop starts on 9545 and ganache-cli on 8545).

To best see Ganache UI in action, let’s try deploying the same SimpleStorage (with a few small enhancements) contract from the previous exercise to the chain instance it instantiates.

Creating a Workspace

Upon opening Ganache UI, the first screen you should see is shown below. Select “New Workspace>> Ethereum” (depending on your version you should also see the Corda and Filecoin flavors listed in the dropdown).

Workspace section of Ganache

From here, you’ll be presented with a file picker wherein you can navigate to the project we created earlier and select the truffle-config.js file.

All going well you should be presented with the accounts screen we saw earlier. Feel free to take a browse through the tabs to begin familiarizing yourself.

Migrating our contracts to Ganache UI

Next up we’re going to migrate our contracts (with a few twists) to the chain instance instantiated by Ganache UI on port 7545. This will give us a great way to visually inspect what’s happening not only on our testnet, but also with the contract itself, as you’ll see in a moment.

Before we can migrate, we’ll need to update our truffle-config.js file to include the new network as a destination. Because we used truffle init to create our project, it handily includes a number of commented destinations under the networks entry. As such you’ll be able to scroll down and uncomment (currently lines 45-49 at the time of writing). Note that we have to change port to 7545

development: { host: “127.0.0.1”, port: 7545, network_id: “*”, },

Awesome, we now have a new network we can migrate to! For reference, this same principle applies when migrating to public networks (such as testnets or mainnet; the Ethereum of equivalent of staging and production environments).

Go ahead and run the following, noting the use of the --network flag that allows us to specify a given network that we want to target.

$ truffle migrate --network development

Assuming this ran successfully, you’ll now see some corresponding activity in Ganache UI. Of note are the transactions listed under the “Transactions” tab and all the contract information (such as storage, etc) surfaced under the “Contracts” tab. This is a really helpful feature of Truffle and Ganache: the integration of both the testnet environment and smart contract values, updated dynamically. To have all this visually is really powerful for developing and debugging a contract.

Transaction information on Ganache GUI

Note the Storage (state) section in our “Contracts” section:

Contract information on Ganache GUI

Last, let’s update our contract to include an event that is emitted every time a new value is set (we’ll learn about events in more detail later in this section). Copy and paste the following over your existing SimpleStorage.sol.

// SPDX-License-Identifier: MIT pragma solidity >=0.4.21 <0.7.0; contract SimpleStorage { uint storedData; event setEvent(uint newValue); function set(uint x) public { storedData = x; emit setEvent(x); } function get() public view returns (uint) { return storedData; } }

We’ll now make use of the --reset flag when re-running the migration command to forcibly replace the contract. Note that this will result in a new contract address.

$ truffle migrate --network development --reset

Let’s now jump back into the Truffle console, this time using the console command (vs develop which also spins up a ganache instance, which would be redundant this time).

$ truffle console --network development

Like earlier, we can now send the following to set the value within our SimpleStorage.

$ let contract = await SimpleStorage.deployed() $ contract.set(888)

If all has been successful, you’ll now see both a reference to setEvent in the logged output. In addition, you’ll also be able to navigate to the events tab within Ganache UI and also see it there.

Conclusion

Great! You’ve now successfully familiarized yourself with Ganache UI and in doing so hopefully getting a little more comfortable with both some of the core Ethereum constructs and the basic elements in the development lifecycle.

We know this may be a bit out of your comfort zone, but now that you have a basic understanding of Truffle, you’ll be able to start playing around with the Solidity we’re going to start learning next!

After we go through Solidity fundamentals and Security, we’re going to dive deeper into elements of development on Truffle so you can feel even more confident and capable as a developer.

Before all that, though, we want to introduce one more tool to help you play around with Solidity and other smart contract development languages: Remix.

Additional Material