Learn how to install truffle and compile our first smart contract with Solidity
Table of Content
In this article I will guide you through a complete step by step guide about how to configure your machine and setup to have your first smart contract running and installed on a Blockchain.
Warning
This article was developed using Truffle v5.5.3 (core: 5.5.3), Ganache v7.0.1, Solidity - 0.8.12 (solc-js), Node v17.7.0 and Web3.js v1.5.3
Steps
The steps we are going to make are listed below
Configure our environment and install required tools: truffle, ganache.
Design a simple smart contract with Solidity and compile it.
Deploy our smart contract bytecode.
Configure our environment and install required tools
This is the basic step required before starting. We need to install some tools to make our development easier and faster.
Installing the tools
The first thing is to install the tools called truffle and ganache that allow us to have a easy development environment in our local computer. However, as requirements, we need to have NodeJS v12 or later installed. To do so, we will use nvm (a Node Version Manager) to setup the specific version.
Install NVM
To install or update nvm, you should run the install script. To do that, you may either download and run the script manually, or use the following cURL or Wget command:
Select the default version or any other greater than v12
1
nvm install stable
A successful installation will report
1
2
3
4
5
6
Downloading and installing node v17.7.0...
Downloading https://nodejs.org/dist/v17.7.0/node-v17.7.0-linux-x64.tar.xz...
###################################################################################################################### 100,0%Computing checksum with sha256sum
Checksums matched!
Now using node v17.7.0 (npm v8.5.2)
Set the downloaded Node JS version
At this point, the nvm tool already downloaded the requested version. The last step, is to make it active
This is required since nvm tool allow us to have multiple NodeJS version installed at the same time in our local environment.
1
2
nvm use stable
Now using node v17.7.0 (npm v8.5.2)
Install Truffle
After installing NodeJS, next we require to install truffle tool. The installation process is as simple as running
1
npm install -g truffle
Wait for download to finish, and you should have truffle installed globally in your system.
To make sure truffle was completely installed, we check the installed tool version
Next thing we need to focus on: Solidity programming and contract design.
Building a contract with Solidity
For article purposes, we are going to design and build a simple example of Solidity contract that just writes arbitrary information to the ledger and reads data from it.
For this purpose, we assume following requirements:
The contract must be installable and must keep a reference to contract owner
The contract must allow anyone to register the specified data model
The contract must allow anyone to fetch the previously registered information. The lookup will be done by key.
So, truffle created a sample file called Demo.sol with some basic code
1
cat contracts/Demo.sol
1
2
3
4
5
6
7
// SPDX-License-Identifier: MIT
pragma solidity>=0.4.22<0.9.0;contractDemo{constructor()public{}}
We need to update this Demo.sol file with our own code
Change 1: setup latest Solidity compiler version
We set the version of solidity v0.8.12. The modified code is
1
2
3
4
5
6
7
// SPDX-License-Identifier: MIT
pragma solidity0.8.12;contractDemo{constructor()public{}}
Change 2: we set the contract owner
In order to set the contract owner, we need to modify constructor function so that the caller of the contract get stored in the Blockchain. To do so, we need to save this information as part of the contract state data.
1
2
3
4
5
6
7
8
9
10
11
12
13
// SPDX-License-Identifier: MIT
pragma solidity0.8.12;contractDemo{// owner keeps the address of which installed the contract
addressprivateowner;constructor()public{// we store the address who installed this contract as owner
owner=msg.sender;}}
Change 3: create the data model
Next step, is to defined the data model we need to store the information in the ledger. This is just a tiny example to show you that Solidity can hold more information that what usually is been saved in an ERC20, ERC721, etc.
Our data model, will be called Record and will contain following attributes:
Id: numeric value that works as a key. This data is provided by the user.
Data: string data. This data is provided by the user.
Knowing previous information, we can model our structure as
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
/**
Record is our structure definition for our data model
*/structRecord{/**
id is the unique identifier of the record
*/uintid;/**
content is the arbitrary content of the record
since this is an example, we do not focus on gas optimization
*/stringcontent;}
You can define your own type by creating a struct.
They are useful for grouping together related data.
Structs can be declared outside of a contract and imported in another contract.
Add our new struct Record to our contract and your code will look like:
// SPDX-License-Identifier: MIT
pragma solidity0.8.12;contractDemo{// owner keeps the address of which installed the contract
addressprivateowner;/**
Record is our structure definition for our data model
*/structRecord{/**
id is the unique identifier of the record
*/uintid;/**
content is the arbitrary content of the record
since this is an example, we do not focus on gas optimization
*/stringcontent;}constructor()public{// we store the address who installed this contract as owner
owner=msg.sender;}}
Change 4: create a function to read data from Blockchain
According to our self assigned requirement:
The contract must allow anyone to fetch the previously registered information. The lookup will be done by key.
After populating the function with requested code it will look like:
1
2
3
4
5
6
7
functionreadRecord(uintkey)externalviewreturns(Recordmemory){// lookup requested record by given key
Recordmemoryr=recordData[key];// if r is not found by key, returned r object will be populated with default values
// default data Record { id: 0, content: "" } will works as NULL
returnr;}
As you can see, there is a new variable called recordData that is new, and is defined as
1
mapping(uint=>Record)privaterecordData;
Change 5: create a function to write data to Blockchain
According to our self assigned requirement:
The contract must allow anyone to register the specified data model
After populating the function with requested code it will look like:
1
2
3
4
5
6
7
functionwriteRecord(uintkey,stringmemorydata)externalreturns(bool){// create a new record item from user input parameters
Recordmemoryr=Record({id:key,content:data});// store item into the blockchain
recordData[key]=r;returntrue;}
Deploy our solidity smart contract
After designing and building our Solidity contract, we get the following code
// SPDX-License-Identifier: MIT
pragma solidity0.8.12;contractDemo{// owner keeps the address which installed the contract
addressprivateowner;/**
Record is our structure definition for our data model
*/structRecord{/**
id is the unique identifier of the record
*/uintid;/**
content is the arbitrary content of the record
since this is an example, we do not focus on gas optimization
*/stringcontent;}mapping(uint=>Record)privaterecordData;constructor()public{// we store the address who installed this contract as owner
owner=msg.sender;}functionwriteRecord(uintkey,stringmemorydata)externalreturns(bool){// create a new record item from user input parameters
Recordmemoryr=Record({id:key,content:data});// store item into the blockchain
recordData[key]=r;returntrue;}functionreadRecord(uintkey)externalviewreturns(Recordmemory){// lookup requested record by given key
Recordmemoryr=recordData[key];// if r is not found by key, returned r object will be populated with default values
// default data Record { id: 0, content: "" } will works as NULL
returnr;}}
Compiling the contract
Now that our Demo contract is designed, our next step it to compile it. We will use truffle compile to do it.
1
truffle compile
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
Compiling your contracts...
===========================✔ Fetching solc version list from solc-bin. Attempt #1✔ Downloading compiler. Attempt #1.> Compiling ./contracts/Demo.sol
> Compiling ./contracts/Migrations.sol
> Compilation warnings encountered:
Warning: Visibility for constructor is ignored. If you want the contract to be non-deployable, making it "abstract" is sufficient.
--> project:/contracts/Demo.sol:27:3:
|27| constructor() public {| ^ (Relevant source part starts here and spans across multiple lines).
> Artifacts written to /home/r00t/demo/build/contracts
> Compiled successfully using:
- solc: 0.8.12+commit.f00d7308.Emscripten.clang
Deploying the contract
A way to see the result of the compilation is to review the file under ./build/contracts/Demo.json. Within that file, the compiled bytecode can be seen. In this example, this is the bytecode i get.
In order to deploy our contract in a testing environment, we use ganache tool, so that we can have a local EVM with some predefined accounts. To run ganache simply type in your terminal ganache.
Compiling your contracts...
===========================> Everything is up to date, there is nothing to compile.
Starting migrations...
======================> Network name: 'ganache'> Network id: 1646908313472> Block gas limit: 30000000(0x1c9c380)1_initial_migration.js
====================== Deploying 'Migrations' ----------------------
> transaction hash: 0xfaa7a45c83ddedd424fa2e55f00e22d1255e032b86d8f93a8e7ec4aa0609f9c5
> Blocks: 0 Seconds: 0 > contract address: 0x5EeC2846bf49d445C405b67e59b56e335163a78C
> block number: 1 > block timestamp: 1646908603 > account: 0xeadcE979B7D8EBb7970417b452D08291c8265521
> balance: 999.99915577075
> gas used: 250142(0x3d11e) > gas price: 3.375 gwei
> value sent: 0 ETH
> total cost: 0.00084422925 ETH
> Saving migration to chain.
> Saving artifacts
-------------------------------------
> Total cost: 0.00084422925 ETH
Summary=======> Total deployments: 1> Final cost: 0.00084422925 ETH
It cost about $0.00084422925 \ ETH$ using $250142$ gas. If we run this same deployment in the Ethereum mainnet, the $ETH$ gas cost today is $23$ gwei, so that the deployment cost would be
$$
250142 \cdot 23 / 10^9 = 0.005753266 \ ETH
$$
At current exchange rate of $(1 \ ETH = 2.357,66 \ EUR)$, this would be $13,56 \ €$ for our simple read-write contract.
However, in our ganache TEST environment, all deployments are FREE.
Conclusion
And this is all, the steps to prepare, design, build and deploy an smart contract into Ethereum or any other EVM compatible networks. I just would like to mention two thing:
If you are planning to deploy and run serious DApps on any Blockchain network, make sure you properly TEST all your features.
If you deal with people money, make sure you relay on external security auditors to verify your code quality, errors, vulnerabilities and so on.
Take into consideration some smart contract upgrade patterns.
Thanks for checking this out and I hope you found the info useful! If you have any questions, don't hesitate to write me a comment below. And remember that if you like to see more content on, just let me know it and share this post with your colleges, co-workers, FFF, etc.