Back

# How to install truffle, compile and run our first smart contract with Solidity

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

1. Configure our environment and install required tools: truffle, ganache.
2. Design a simple smart contract with Solidity and compile it.
3. 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:

 1  curl -o- https://raw.githubusercontent.com/nvm-sh/nvm/v0.39.1/install.sh | bash 

After successful download, add required completion script to your bashrc

 1 2 3  export NVM_DIR="$HOME/.nvm" [ -s "$NVM_DIR/nvm.sh" ] && \. "$NVM_DIR/nvm.sh" # This loads nvm [ -s "$NVM_DIR/bash_completion" ] && \. "$NVM_DIR/bash_completion" # This loads nvm bash_completion  #### Download NodeJS v12+ with NVM First, run nvm list to get the list of available node versions  1  nvm list    1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18   v8.10.0 v8.17.0 v10.24.1 v13.7.0 -> v17.0.1 default -> node (-> v17.0.1) iojs -> N/A (default) unstable -> N/A (default) node -> stable (-> v17.0.1) (default) stable -> 17.0 (-> v17.0.1) (default) lts/* -> lts/gallium (-> N/A) lts/argon -> v4.9.1 (-> N/A) lts/boron -> v6.17.1 (-> N/A) lts/carbon -> v8.17.0 lts/dubnium -> v10.24.1 lts/erbium -> v12.22.9 (-> N/A) lts/fermium -> v14.18.3 (-> N/A) lts/gallium -> v16.13.2 (-> N/A)  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  1  truffle version   1 2 3 4 5  Truffle v5.5.3 (core: 5.5.3) Ganache v7.0.1 Solidity - 0.8.12 (solc-js) Node v17.7.0 Web3.js v1.5.3  ### Install Ganache To install ganache globally, run:  1  npm install ganache --global  Once installed globally, you can start ganache right from your command line:  1  ganache  ## Design a simple smart contract with Solidity and compile it Now that we have some basic tools installed, lets code our smart contract! ### Creating a Truffle project To use most Truffle commands, you need to run them against an existing Truffle project. So the first step is to create a Truffle project. In order to create an empty project, you need to run init command  1  truffle init    1 2 3 4 5 6 7 8 9 10 11 12  Starting init... ================ > Copying project files to /home/sergio/Downloads/proyectos/zuretzat-sc/new 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  Now, pick a contract name, for example Demo and scafold your new project  1  truffle create contract Demo  Once this operation is completed, you’ll now have a project structure with the following items: • contracts/: Directory for Solidity contracts • migrations/: Directory for scriptable deployment files • test/: Directory for test files for testing your application and contracts • truffle.js: Truffle configuration file Apart from previous directories, the content of a bare minimum project is as follows:   1 2 3 4 5 6 7 8 9 10 11  . ├── contracts │ ├── Demo.sol │ └── Migrations.sol ├── migrations │ └── 1_initial_migration.js ├── package.json ├── test └── truffle-config.js 3 directories, 5 files  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; contract Demo { 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 solidity 0.8.12; contract Demo { 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 solidity 0.8.12; contract Demo { // owner keeps the address of which installed the contract address private owner; 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 */ struct Record { /** id is the unique identifier of the record */ uint id; /** content is the arbitrary content of the record since this is an example, we do not focus on gas optimization */ string content; }  • 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:   1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29  // SPDX-License-Identifier: MIT pragma solidity 0.8.12; contract Demo { // owner keeps the address of which installed the contract address private owner; /** Record is our structure definition for our data model */ struct Record { /** id is the unique identifier of the record */ uint id; /** content is the arbitrary content of the record since this is an example, we do not focus on gas optimization */ string content; } 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. we can model the Solidity function as  1 2 3 4  function readRecord() external view returns(Record memory) { Record memory r; return r; }  After populating the function with requested code it will look like:  1 2 3 4 5 6 7  function readRecord(uint key) external view returns(Record memory) { // lookup requested record by given key Record memory r = 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 return r; }  As you can see, there is a new variable called recordData that is new, and is defined as  1  mapping(uint => Record) private recordData;  #### 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 we can model the Solidity function as  1 2 3  function writeRecord(uint key, string memory content) external returns(bool) { return true; }  After populating the function with requested code it will look like:  1 2 3 4 5 6 7  function writeRecord(uint key, string memory data) external returns(bool) { // create a new record item from user input parameters Record memory r = Record({id:key, content:data}); // store item into the blockchain recordData[key]=r; return true; }  ## Deploy our solidity smart contract After designing and building our Solidity contract, we get the following code   1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47  // SPDX-License-Identifier: MIT pragma solidity 0.8.12; contract Demo { // owner keeps the address which installed the contract address private owner; /** Record is our structure definition for our data model */ struct Record { /** id is the unique identifier of the record */ uint id; /** content is the arbitrary content of the record since this is an example, we do not focus on gas optimization */ string content; } mapping(uint => Record) private recordData; constructor() public { // we store the address who installed this contract as owner owner = msg.sender; } function writeRecord(uint key, string memory data) external returns(bool) { // create a new record item from user input parameters Record memory r = Record({id:key, content:data}); // store item into the blockchain recordData[key]=r; return true; } function readRecord(uint key) external view returns(Record memory) { // lookup requested record by given key Record memory r = 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 return r; } }  ### 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.  1  0x608060405234801561001057600080fd5b50336000806101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff160217905550610666806100606000396000f3fe608060405234801561001057600080fd5b50600436106100365760003560e01c8063f2e0d5741461003b578063fb891df81461006b575b600080fd5b610055600480360381019061005091906102d4565b61009b565b60405161006291906103e6565b60405180910390f35b6100856004803603810190610080919061053d565b61016a565b60405161009291906105b4565b60405180910390f35b6100a36101cd565b600060016000848152602001908152602001600020604051806040016040529081600082015481526020016001820180546100dd906105fe565b80601f0160208091040260200160405190810160405280929190818152602001828054610109906105fe565b80156101565780601f1061012b57610100808354040283529160200191610156565b820191906000526020600020905b81548152906001019060200180831161013957829003601f168201915b505050505081525050905080915050919050565b600080604051806040016040528085815260200184815250905080600160008681526020019081526020016000206000820151816000015560208201518160010190805190602001906101be9291906101e7565b50905050600191505092915050565b604051806040016040528060008152602001606081525090565b8280546101f3906105fe565b90600052602060002090601f016020900481019282610215576000855561025c565b82601f1061022e57805160ff191683800117855561025c565b8280016001018555821561025c579182015b8281111561025b578251825591602001919060010190610240565b5b509050610269919061026d565b5090565b5b8082111561028657600081600090555060010161026e565b5090565b6000604051905090565b600080fd5b600080fd5b6000819050919050565b6102b18161029e565b81146102bc57600080fd5b50565b6000813590506102ce816102a8565b92915050565b6000602082840312156102ea576102e9610294565b5b60006102f8848285016102bf565b91505092915050565b61030a8161029e565b82525050565b600081519050919050565b600082825260208201905092915050565b60005b8381101561034a57808201518184015260208101905061032f565b83811115610359576000848401525b50505050565b6000601f19601f8301169050919050565b600061037b82610310565b610385818561031b565b935061039581856020860161032c565b61039e8161035f565b840191505092915050565b60006040830160008301516103c16000860182610301565b50602083015184820360208601526103d98282610370565b9150508091505092915050565b6000602082019050818103600083015261040081846103a9565b905092915050565b600080fd5b600080fd5b7f4e487b7100000000000000000000000000000000000000000000000000000000600052604160045260246000fd5b61044a8261035f565b810181811067ffffffffffffffff8211171561046957610468610412565b5b80604052505050565b600061047c61028a565b90506104888282610441565b919050565b600067ffffffffffffffff8211156104a8576104a7610412565b5b6104b18261035f565b9050602081019050919050565b82818337600083830152505050565b60006104e06104db8461048d565b610472565b9050828152602081018484840111156104fc576104fb61040d565b5b6105078482856104be565b509392505050565b600082601f83011261052457610523610408565b5b81356105348482602086016104cd565b91505092915050565b6000806040838503121561055457610553610294565b5b6000610562858286016102bf565b925050602083013567ffffffffffffffff81111561058357610582610299565b5b61058f8582860161050f565b9150509250929050565b60008115159050919050565b6105ae81610599565b82525050565b60006020820190506105c960008301846105a5565b92915050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052602260045260246000fd5b6000600282049050600182168061061657607f821691505b6020821081141561062a576106296105cf565b5b5091905056fea2646970667358221220e245225e3554a6b6a54cc859d5a0d5d4744ee8e0d13146de68f3caa0f0510f7564736f6c634300080c0033  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.  1  ganache  And it will start a RPC server   1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51  ganache v7.0.3 (@ganache/cli: 0.1.4, @ganache/core: 0.1.4) Starting RPC server Available Accounts ================== (0) 0xeadcE979B7D8EBb7970417b452D08291c8265521 (1000 ETH) (1) 0x574537620d65FB8fB1d44dffFA1b6b350503dFdA (1000 ETH) (2) 0x1093BC537E6BEa991111B30280c737089b20af14 (1000 ETH) (3) 0x45ff62a6fAbb54020C16728eC9bC46E896BCb88E (1000 ETH) (4) 0xcabD449394A29f91b92cB790CD50edA32A11C23b (1000 ETH) (5) 0xA731Cf52A50af2a4C6653ACD4bbFeC72A2BC9A08 (1000 ETH) (6) 0x7440322BB3CDa08F31d454e710690D44b6b2A9ED (1000 ETH) (7) 0x83D600090213Bd86ccA983455728C92bFB433DC4 (1000 ETH) (8) 0xedf61b529F8feB023807C103d3336827BE6D88A7 (1000 ETH) (9) 0xE4c62D0eAce8C6f258505e24f5e2aD687501537F (1000 ETH) Private Keys ================== (0) 0x1677700009b08909aa22b9b37be7bb67b323e3de69dd07d7c771c24d75487950 (1) 0x61c335032c0eaae0c09f73c22355d34a3b7a91737152f4204c2c8141c4a6bbb6 (2) 0xedd34a9bb26c1e4386e8870f67048de1bb5c87c0253c0bca45c71c89bde63691 (3) 0x69a16039ac3a15dc53e0b109a0303f5dc3a744ed3533d6dd6b289fccd8446677 (4) 0x7a3f6ba6705545caecbd41f59784cc0e0c6a7b6f588344977e8a4014767879e7 (5) 0xffc5fa88ff2c879803ada4eb58173016d36172feb3c21fc6e87507022bddfc19 (6) 0xe0a2991cb878fd7ce0716a4aaa6c02c2e58679835c6b40240af20f72755e6c33 (7) 0xd79b1b95bcb3fd472217df57b908943d16ed4bc8cc7fcb067c6c5db77dee7fca (8) 0xe2f1af569e81be8f2df8a1b31cc755d048aaeb7b28f2172b76f5caf82ae94e5d (9) 0xb049f424e807571269e84c580b19e997a4ae48ac031ae0ab79c2572d13eeb31b HD Wallet ================== Mnemonic: drip purpose object edit traffic refuse fresh inherit entry length badge violin Base HD Path: m/44'/60'/0'/0/{account_index} Default Gas Price ================== 2000000000 BlockGas Limit ================== 30000000 Call Gas Limit ================== 50000000 Chain Id ================== 1337 RPC Listening on 127.0.0.1:8545  After running ganache it will provide you and endpoint to connect with. In my case the endpoint is located at http://127.0.0.1:8545. To connect to this endpoint, modify the truffle-config.js file and define your test network as ganacheNet like following snippet  1 2 3 4 5 6  networks: { ganacheNet: { host: "127.0.0.1", port: 8545, network_id: "*" }  Now, to deploy the contract against specified network, use truffle deploy command indicating which target network you want to use.  1  truffle deploy --network ganacheNet  where ganacheNet is just the name given in the truffle-config.js A successful contract deployment will report to you the contract address and the cost of the operation.   1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38  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  • Deployed contract addess: 0x5EeC2846bf49d445C405b67e59b56e335163a78C • gas used: 250142 • gas price: 3.375 gwei 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:

1. If you are planning to deploy and run serious DApps on any Blockchain network, make sure you properly TEST all your features.
2. If you deal with people money, make sure you relay on external security auditors to verify your code quality, errors, vulnerabilities and so on.
3. Take into consideration some smart contract upgrade patterns.