Description / Intro
With the cryptocurrency prices regaining momentum since the last quarter of 2020, the Decentralized Finances have taken the news headlines once again, fuelling the interest in technologies used to develop Smart Contracts for the Blockchain.
Although there are many articles and online resources that may get you started with these technologies, more often than not, they lack certain architectural details to have a good understanding of what is happening behind the scenes on each step.
Problem to Solve
Since this is a fast-growing ecosystem, technologies change rapidly, and it is a challenge to learn Smart Contract development navigating through outdated or not entirely accurate documentation and tutorials.
This article aims to give an up-to-date overview of how to smoothly get started with Smart Contract development, making architecture the backbone of the process.
Roadmap
We will do a quick but comprehensive walk-through of the Ethereum Architecture to understand the role that each tool that we will install plays in the Solidity lifecycle and then try to give precise instructions to get the development environment setup.
Let’s jump right into it.
Journey
The Ecosystem
A Blockchain can be described as a ledger database that is distributed across a network of computers.
The records on this distributed ledger database are publicly accessible, and they are called blocks because the data is stored in sequential batches or “blocks”.
A Blockchain is a chain of these records because each one is cryptographically linked to its parent using a Merkle Tree. The data of a block cannot be altered without changing all the subsequent blocks.
Since the blockchain is distributed across all the computers in the network, a change would require the entire network’s consensus. All the computers in the network must accept every block of the whole blockchain, so they have the same data. These insertions of new blocks are agreed to through a consensus mechanism.
For the Ethereum protocol, the consensus mechanism is currently proof-of-work. Anyone who wants to add new blocks to the blockchain must solve a mathematical puzzle that requires a lot of computing power. Having solved this puzzle proves that you have spent the computational resources. This is known as mining and is rewarded in ETH by the network. The large amount of resources needed to produce the block prevents the submission of fraudulent blocks.
The moving parts
Before jumping into specifics, it is convenient to clarify some concepts which will help you make sense of all the moving parts required to develop in the Ethereum network.
Ethereum is an open-source blockchain that gives us the ability to execute programs in a distributed runtime environment called Ethereum Virtual Machine (or EVM), whose state is agreed on by every node in the network. Every node in the network keeps a copy of this computer’s state and can request to perform arbitrary computation. The other nodes on the network verify, validate, and execute the computation, causing a state change in the EVM, committed and propagated throughout the entire network.
Once transactions are verified as valid and added to the blockchain, they can’t be altered later since they are cryptographically linked to the previous ones, ensuring that all the transactions are executed with the correct permissions.
The software programs developed to run on the EVM are called Smart Contracts.
Like Classes in object-oriented programming, Smart Contracts are snippets of code containing state data and functions (behavior) to manipulate such state data.
The most popular high-level language to write Smart Contracts is Solidity.
It is a statically typed language heavily influenced by C++, JavaScript, and Python.
Once compiled to EVM bytecode, it can be executed on the Ethereum network.
Solc is the Solidity Compiler used to produce the EVM bytecode.
The Ethereum Network offers a JSON-RPC interface to deploy and execute Smart Contracts. Web3.js is a popular javascript library to send calls to this JSON-RPC.
To send requests to the various Ethereum networks, you would need to stand up and maintain a full Ethereum node, which can be a challenging task. Luckily, services like Infura and the Cloudflare Ethereum Gateway allow us to send JSON-RPC calls without managing a full Ethereum node.
However, while developing a Smart Contract, it is necessary to run them locally without sending them to a public network (even a test one).
Ganache is a locally hosted instance of Ethereum that runs in memory and exposes the same JSON-RPC interface as any Ethereum full node.
Together with Ganache, it is necessary to install Truffle. It is a development environment to test, compile and manage the resulting assets. It also provides an interactive console to interact directly with contracts, dependency management, and a scriptable and extensible migration framework.
Metamask is a web browser extension that allows interaction with the Smart Contracts deployed to the Ethereum Network through its JSON-RPC from any web page. It uses Web3 under the hood.
Prerequisites: Node v12.23.1 and NPM or Yarn.
Install Ganache: Ganache will be our local development ethereum network. It exposes the same APIs and behavior as a production ethereum network, but it resides only in the local computer.
There are two flavors to get Ganache (no pun intended):
Ganache: Head to https://www.trufflesuite.com/ganache and download the version for your platform. Execute the installer.
Ganache CLI: It is the command-line version of Ganache.
You can get it with NPM
npm install -g ganache-cli
Check the CLI execution options here
Install Truffle
npm install -g truffle
If you’re using Windows, make sure you check their documentation regarding naming conflicts.
Install Metamask
Metamask is a tool (bundled as a browser extension) that allows you to interact with the Ethereum network through Web3.js.
Head to the official Metamask website, and check the downloads page to get the version for your browser.
Install the solidity linter
Solhint is a popular linter for Solidity
npm install -g solhint
Install Web3
Web3 is a library meant to be used with a node environment and the browser as well.
To get it for node:
npm install web3
To get it in the browser, use a CDN like CDNJs:
Setting up your IDE or Editor
VS Code
Install the plugin to have solidity language syntax highlighting:
https://marketplace.visualstudio.com/items?itemName=JuanBlanco.solidity
Or a more advanced version that provides additional visualization tools
https://marketplace.visualstudio.com/items?itemName=tintinweb.solidity-visual-auditor
Webstorm or IntelliJ
Install the plugin to get support for the solidity language:
https://plugins.jetbrains.com/plugin/9475-intellij-solidity
Install the plugin to have integration with the solidity linter:
https://plugins.jetbrains.com/plugin/10177-solidity-solhint
Starting the Development Network and connecting Metamask to it
To check that everything got correctly installed, we’re going to develop a dead-simple contract.
Let’s create a directory to hold our little project:
mkdir my-first-smart-contractcd my-first-smart-contract
Let’s initialize a Truffle project:
truffle init
This command will create:
- Contracts directory
- Migrations directory
- Tests directory
- Truffle Configuration file
We’re going to open our editor in the directory we have just created and edit the truffle.config.js file.
Look for the key “networks” of this file’s exported module.
You will find a commented entry for a network called “development”, which is the special network spun up by truffle when executing the truffle develop command.
Let’s uncomment the development network.
The only change is to put an integer number as a string in the network_id (it will be required later on to connect Metamask with the development network). For example, you can put “1337”. You can leave all the fields of the network with their default values.
Save the file.
Let’s start the ganache local development ethereum network built-in within truffle:
truffle develop
This command will start the Test RPC server in port 9545 by default.
And now, let’s connect Metamask to our local development network.
- Click the Metamask extension icon in the browser bar.
- Click the Account icon on the top-right corner of the extension window.
- Click Settings
- Scroll down to the Networks section and click it
- Click “Add Network”
- Network name: Enter a meaningful name, such as “Truffle Local” or so
- New RCP URL: Enter the local URL for the Truffle Test RPC server. (http://127.0.01:9545 by default)
- Chain ID: Enter the value you put in the network_id field of the truffle config file’s development network, in our case 1337.
- You can leave blank the other fields.
- Click Save.
- You should be able now to see all the Test Accounts in the Truffle server from within Metamask.
Develop your first Smart Contract
A “smart contract” is a program that runs on the Ethereum Virtual Machine.It has behavior coded as functions and state data.
Once deployed to a network, it resides at a specific address on that network blockchain.
Smart contracts are a special type of Ethereum account, meaning they have an ETH balance and can send transactions over the network. The difference with a regular account is that they are not managed directly by users as standard accounts, but instead, they are deployed to the network and run as programmed.
Users can interact with a smart contract by submitting transactions that execute a function on the smart contract.
Let’s add a new file in the /contracts directory of our project. We’re going to call it Counter.sol
Let’s edit the Counter.sol file, adding the following code:
// SPDX-License-Identifier: MITpragma solidity >=0.4.22 <0.9.0;contract Counter { uint private count; constructor(uint _initialCount) public { count = _initialCount; } function incrementBy(uint _increment) public { count = count + _increment; } function getCount() public view returns (uint) { return count; }}
A complete solidity tutorial is beyond the scope of this article, but let’s go piece by piece trying to explain what we’ve just done.
// SPDX-License-Identifier: MIT
This is a single-line comment in solidity, but this particular comment in the first line of the contract has a special use. It is a Software Package Data Exchange License Identifier. The compiler won’t validate its presence, but it will tag the contract as UNLICENSED, showing a warning if it does not find it. It is considered good practice to add an SPDX license identifier to the contracts.
pragma solidity >=0.4.22 <0.9.0;
This is a pragma directive. They’re always local to the current source file, and it tells the solidity compiler the version required to compile the current file. This particular pragma says that the compiler version should be higher or equal to 0.4.22 but less than 0.9.0.
contract Counter {
As mentioned before, contracts are comparable to classes in object-oriented languages.
We’re declaring this class.
uint private count;
We’re here declaring a variable stored in the Network Storage, and it will be private to this contract, so it can not be read from outside directly.
Solidity is a statically typed language. The type of these particular variables is an unsigned integer.
constructor(uint _initialCount) public { count = _initialCount;}
This is the constructor method of the contract, and when invoked, it creates a new instance of the contract that will reside in a Network address. This new instance will be initialized with the private count variable with the value received by the contract as the parameter. So you could create a new contract instance with the variable count having a value chosen at the time of creating the new contract instance.
function incrementBy(uint _increment) public { count = count + _increment;}
This public function will be exposed by the contract to the network and will be publicly accessible. It also needs an unsigned integer as a parameter, and it will use it to increment the value of the counter.
function getCount() public view returns (uint) { return count;}
This is a public function as well, but it is marked as a view. This means that invoking this function won’t change the state of the contract. It will only return the current value of the counter variable.
Now that we covered the contract parts, let’s compile it and deploy it to our development network.
Truffle provides an asset pipeline and migration framework that we can use to deploy our assets to any ethereum network.
It also provides a CLI utility to make the process even easier.
If you inspect your project directory, you‘ll see a migrations folder. It already contains an initial migration that deploys the Migrations.sol contract, a utility contract that truffle uses to keep track of the latest contract deployed to the network.
We will create another migration to deploy our Counter contract.
Although migrations can be created by hand, truffle provides a create utility command to automate this process.
Go to the root directory of the project and run truffle create migration deploy_counter (truffle create is the command, migration is the type of asset to be created, and deploy_counter is just an arbitrary name for the migration).
This is going to create a new javascript file within the migrations directory, with a name that will look like #########_deploy_counter.js where ######### is the milliseconds from epoch at the time of running the create command.
You’ll see the initial migration has the number 1. Any further migration needs to have increasing numbers, and prefixing them with getTime from epoch makes sure the numbers are unique, incremental. The migrations are run in the order in which they were created.
Now open with your editor the newly created migration file. We will write the migration code to get the compiled Counter contract deployed.
const Counter = artifacts.require(‘Counter’);module.exports = function(_deployer) { _deployer.deploy(Counter, 1);};
We import the compiled Counter contract artifact and then export a function that uses such artifact to deploy the contract. The second parameter is the counter variable’s initial state (remember the parameter required by the contract’s constructor method?).
Once the migration is created and updated to deploy the contract, make sure you’re running truffle develop to have the “develop” network spun up. Then run truffle migrate from the root directory of the project.
As a result of the migration process, you should get an output similar to:
truffle migrateCompiling your contracts…===========================> Everything is up to date, there is nothing to compile.Starting migrations…======================> Network name: ‘development’> Network id: 5777> Block gas limit: 6721975 (0x6691b7)1614165891_deploy_counter.js============================Deploying ‘Counter’ — — — — — — — — — -> transaction hash: 0x84076d471e163434037fd789ae646358810444a463e644aa394e0245e684bdd3> Blocks: 0 Seconds: 0> contract address: 0x8a080f066f60072aEAFDDC310EeDD3d09980b315> block number: 3> block timestamp: 1614167141> account: 0x5746dF578F3b10B83b1E5FbBd533bcFf739a7F22> balance: 99.99294998> gas used: 118220 (0x1cdcc)> gas price: 20 gwei> value sent: 0 ETH> total cost: 0.0023644 ETH> Saving migration to chain.> Saving artifacts — — — — — — — — — — — — — — — — — — -> Total cost: 0.0023644 ETHSummary=======> Total deployments: 1> Final cost: 0.0023644 ETH
You will find the address of the development ethereum network in which the contract is deployed. Copy it since we’re going to use it.
Now that it is deployed, let’s return to the Truffle console opened when we ran truffle develop.
We will interact with the deployed contract from the console.
The console is a Javascript REPL so that we can use javascript statements on it.
Let’s bring the contract that we just deployed with truffle migrate.
let instance = await Counter.at(“paste here the contract address you copied before”)
This should return the complete Application Binary Interface of the contract and store it in the instance variable**.**
instance.getCount()
It will return something like this:
BN { negative: 0, words: [ 0, <1 empty item> ], length: 1, red: null }
It is a BigNumber object. The value as an integer is the first member of the words array.
Let’s try to change the state data of the contract.
instance.incrementBy(42)
This will return the transaction receipt, which will look similar to this:
{ tx: ‘0x69bbfe16e0c663d9108c9a3b3f35b35fbed2aa1cf6c144566e807521a57acd57’, receipt: { transactionHash: ‘0x69bbfe16e0c663d9108c9a3b3f35b35fbed2aa1cf6c144566e807521a57acd57’, transactionIndex: 0, blockHash: ‘0xfe7b7d181bc5cdb4211730f3ac4107409e8889179593d9eda6a33162a3fdc9f3’, blockNumber: 9, from: ‘0x5746df578f3b10b83b1e5fbbd533bcff739a7f22’, to: ‘0x8a080f066f60072aeafddc310eedd3d09980b315’, gasUsed: 27230, cumulativeGasUsed: 27230, contractAddress: null, logs: [], status: true, logsBloom: ‘0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000’, rawLogs: [] }, logs: []}
Now, if you try to getCount again, you’ll notice that the count has changed as expected.
instance.getCount()BN { negative: 0, words: [ 42, <1 empty item> ], length: 1, red: null }
With this, we have just made sure we can start developing more exciting stuff.
Conclusion
Ethereum is a blockchain network that can be used as a distributed computing environment, allowing us to develop decentralized financial components.
As every distributed environment familiar with the architecture can be more challenging, it is fundamental to get started with the right foot.
We will still cover many things in future articles, such as a more in-depth walkthrough of the Solidity syntax and common data structures and how to develop Decentralized Applications that would interact directly with the Ethereum Network.
But we just made sure of having everything we need in our toolbox to get us started, especially understanding the Ethereum architecture’s mechanics.
Call to Action
Do you want to add Decentralized Financial Components to your application, or have a cool project in mind and don’t know how to materialize it?
Talk to us. We can help!


