Zeppelin - A Gentle Introduction to Ethereum Programming

Two months ago I was asked to build an Ethereum web application as a work test to join Zeppelin, but I didn’t have any idea about blockchain technology at all. I had barely heard of Bitcoin, so there was no other option but to dive in.

This will be a series of posts aimed at software developers who want to ramp up to Ethereum. Please keep in mind that I do not consider myself an expert in this subject, I’d just like to teach you what I learned and save you some time if you are in the same place I was. By the end of the series you should be able to build a fully-fledged smart-contract-enabled web application (also known as DApp) on your own!

Enjoy, and please do not hesitate to reach out with questions, suggestions or feedback.

Index

1. Taking the first steps

1.1. Introduction

1.2. Web3

2. Interacting with a contract

3. Frameworks & Tools in the real world

4. A real DApp, a token marketplace — coming soon


1. Taking the first steps

1.1. Introduction

I’ll assume you have some basic knowledge about computer programming and what a blockchain data structure looks like. If you don’t, please follow this link and come back!

Ethereum

Let’s start by defining Ethereum, or at least, what I understood about it after my research. Ethereum is an open-source public platform, distributed and based on blockchain technology, to run applications without censorship or third-party interference.

Smart Contracts

Smart contracts are just computer programs. We build Ethereum applications based on smart contracts. Bear in mind that even though this concept comes up with Ethereum these days, it was actually proposed by Nick Szabo in 1996 :)

Ethereum Virtual Machine

The EVM is the sandboxed runtime and completely isolated environment for smart contracts in Ethereum. This means every smart contract running inside the EVM has no access to network, file system or other processes.

Gas

Given that Ethereum is a distributed platform, there must be a way to limit the resources available to a given smart contract, otherwise it could starve the whole network’s computing power. Gas solves that issue by fixing a cost for every instruction executed in the EVM. One important thing, is that every transaction is sent to the network with a “gas budget”. If it runs out, the transaction will fail but still gets mined into the blockchain.

Ether (ETH)

It is the Ethereum cryptocurrency token. There is a gas/Ether dynamic price that measures how much ETH will an operation cost. The fee paid to execute a transaction is calculated by multiplying the gas cost and the gas price (the resulting fee is paid in ETH). You can set the gas price for your transaction to any value. However, if the gas price is too low, no one is going to execute your code.

Accounts

Every account is identified by an address. There are two kinds of accounts sharing the same address space. On one hand, we have external accounts controlled by public-private key pairs, commonly owned by people to store ETH. On the other hand, we have contract accounts that are controlled by the code that it’s stored with it. These have a few differences, but one very important to have in mind, is that only external accounts can initiate transactions.

Transactions

A transaction is a message sent from one account to another account. You can send a transaction to another external account in order to transfer ETH. If the target account is a contract account, its code will be executed as well. Note that every transaction that involves code execution will be executed on all nodes of the network. Furthermore, every code run, or transaction execution, will be recorded in the Ethereum blockchain.

Solidity

Solidity is a contract-oriented high-level language, with similar syntax to JavaScript. It is statically typed, supports inheritance, libraries and complex user-defined types. It compiles to EVM assembly, which is run by the nodes.


1.2. Web3

I decided to start interacting with the Ethereum blockchain, by first simply sending ETH from one account to another. I didn’t want to do it with real ETH since I was probably going to make a mess, so I started looking for some testing/fake environment. Reading Manu’s amazing post I found testrpc, that is a node.js Ethereum client for testing and development. Let’s install it and start playing with it:

npm install -g ethereumjs-testrpc
testrpc

You will notice that testrpc has generated 10 addresses with fake ETH you can use without the need to worry about them. This is how testrpc works by default, but you can make a custom initialization following the documentation. It’s important to mention that testrp state is volatile, that is every time you close it, the state of your node and accounts will be cleared.

The next thing you should get to know is Web3.js. It is a JavaScript library that implements the Ethereum JSON RPC. That is, the protocol that we will use to talk to an Ethereum node (in this case, testrpc). To install it, just run:

npm install -g web3@0.20.1

BTW, it is important to install a Web3 0.20.x version, but not the 1.0.0 beta for this exercise. First of all, you need to connect Web3 with your local testing node you are running with testrpc. In order to do that, we will ask Web3 to use a localhost provider. Let’s open a node console and input following lines:

Web3 = require('web3')
provider = new Web3.providers.HttpProvider("http://localhost:8545")
web3 = new Web3(provider)

Please note that we are using the default testrpc port (8545), if you set another one remember to change the provider URL too. Once you have your web3 instance, start by getting the list of accounts you have in your Ethereum node, with their respective balance, by running the following:

web3.eth.accounts.forEach(account => {
balance = web3.eth.getBalance(account);
console.log(balance);
})

You probably noticed that the output is not exactly a list of numbers, that’s because Web3 uses BigNumber objects for number values, since JavaScript is not able to handle big numbers correctly. You can read more about this here.

You should also know that those balances are not expressed in ETH, actually those are wei values, the base unit. 1 ETH is 10¹⁸ wei. Please follow the Ethereum documentation to see more about ETH conversions.

Returning to what we were saying, let’s try to send ETH between two accounts. Just type web3.eth.accounts and pick two of those. Then you can use the sendTransaction method:

from = web3.eth.accounts[0]
to = web3.eth.accounts[1]
transaction = { from: from, to: to, value: 100000 }
transactionHash = web3.eth.sendTransaction(transaction)

That output is the transaction hash, and you can get the transaction information with it:

web3.eth.getTransaction(transactionHash)

You may also want to check that the balances of the accounts that you used have changed. You can validate that with the next commands:

web3.eth.accounts.forEach(account => {
balance = web3.eth.getBalance(account);
console.log(balance);
})

Next, I built a simple UI using HTML and jQuery with a little bit of Bootstrap just to make it pretty. You can take a look at it in my repo. This is what we call a DApp, or decentralised application. That is, an application where part of the backend code runs on a decentralized peer-to-peer network; in this case, the Ethereum network.

UI of the DApp that I built to test ETH transfers

You will find an index.html file for the UI, and an app.js file hosting the interaction with the Ethereum node, that is basically what we described above in conjunction with some jQuery callbacks to populate the UI. Please feel free to clone my repo and give it a try.

=============================================

This is the second part of our Ethereum introduction guide. 

Index

1. Taking the first steps

2. Interacting with a contract

2.1. Introduction to smart contracts in Ethereum

2.2. Your first smart contract

2.3. Deploying a smart contract

2.4. Web3 and smart contracts

3. Frameworks & Tools in the real world

4. A real DApp, a token marketplace — coming soon


2. Interacting with a contract

2.1. Introduction to smart contracts in Ethereum

Well, you already know some basics about Ethereum, you’ve been interacting with an Ethereum node, sent some transactions between accounts, etc. But there is something else that makes Ethereum amazing: smart contracts.

As I explained in the introduction, a smart contract is a program that runs on the EVM. You can build any smart contract to do whatever you want, but today, most are being used for crowdfounding tools like ICOs or token sales. Allow me to explain these.

I will start with crowdfunding, a concept that I’m sure you’re familiar with. Projects do a crowdfunding campaign in order to raise funds to carry out a project. You can issue a digital asset related to your project and immediately sell it to anyone in the world, for almost zero cost. This is what we call an Initial Coin Offering (ICO).

To carry out an ICO with smart contracts, you just need to implement the logic that makes your digital assets tradable and valuable. Sounds great, doesn’t it? These are Ethereum tokens. A token is a digital asset within the Ethereum ecosystem.

Let’s try to analyze all these ideas through an example.

Suppose you have health food company that wants to launch a new brand. You decide to conduct an ICO to raise 20,000 ETH. You offer 10 tokens in return for every 1 ETH you collect, promising that contributors will be able to buy food at your stores with the tokens. To do this, you can develop a token smart contract that stores the proportional amount of tokens for each contributor.

Now, let’s suppose you raised that money, developed your project, and opened your first store. Then, you decide to sell each salad for 1 token. After a week, it turns out that you have an increasing demand, but given that the supply of salads is limited, your customers notice and start trading your tokens as an asset, raising their market value.

This process has been carried out in real life, given Ethereum allows virtually anyone to create their own tradeable, digital asset.


2.2. Your first smart contract

Let’s see how you can build a basic Ethereum token. I will use this example to make an introduction to some Solidity basics.

Please know that this examples are just for learning purposes, you should not use them in production.

pragma solidity ^0.4.0;
contract MyToken {
address public creator;
uint256 public totalSupply;
mapping (address => uint256) public balances;
function MyToken() public {
creator = msg.sender;
totalSupply = 10000;
balances[creator] = totalSupply;
}
 function balanceOf(address owner) public constant returns(uint256){
return balances[owner];
}

function sendTokens(address receiver, uint256 amount)
public returns(bool){
address owner = msg.sender;

require(amount > 0);
require(balances[owner] >= amount);

balances[owner] -= amount;
balances[receiver] += amount;
return true;
}
}

Let’s go step by step. The pragma keyword tells which version of Solidity you are using for your source code. Then, it begins the contract definition initiating with its name, in this case, MyToken. Next, you will find three variables:

  • creator is an address variable to store the owner of the contract.
  • totalSupply is an 256 bit unsigned int to store the amount of tokens willing to be shared with the investors
  • balances is a map from addresses to unsigned ints where the balances of each investor will be stored

Afterwards, you will find the constructor function. As you can see, it is a function with the same name of the contract, and it will be called only once every time a new instance of the contract is deployed to the network. Here is where the owner of the contract gets stored. Since every function call is a transaction, it is possible to know the owner of the contract using the sender of the transaction, that is msg.sender. Finally, the contract defines a total supply of 10,000 tokens, and assigns it to the token creator.

The next function is an easy one: balanceOf simply tells you the balance of an address received by parameter. Maybe you are wondering what the constantkeyword means. Well that’s because Solidity has two kinds of functions, constants and non-constant.

Non-constant functions perform state changes. On the other hand, constant functions are read only once, meaning those don’t perform any state changes, they just read data. Actually, there are two types of constant functions:

  • view declared functions promise not to modify the state (alias to constant)
  • pure declared functions promise not to read from or modify the state

The last function is the one that allows us to trade tokens between addresses. This is a non-constant or transactional function because you will be changing balances. It expects the receiver’s address and the amount of tokens you want to transfer by parameter, and it returns a boolean representing whether the transaction has been successfully executed or not. You can skip the first line, it is just keeping the sender of the function in the owner variable.

Next, you will find two preconditions:

...
require(amount > 0);
require(balances[owner] >= amount);
...

require is one of the methods that you can use to check conditions or make validations. It will eval a condition and revert in case that condition is not met. So, in this case, it is requiring that the amount of tokens to be transferred is greater than zero, and ensuring the sender has enough balance to send that amount.

Finally you are subtracting the required amount of tokens from the owner’s balance and adding it to the receiver’s balance:

...
balances[owner] -= amount;
balances[receiver] += amount;
return true;
}

2.3. Deploying a smart contract

Now, let’s start playing with our contract! You will need to deploy our contract to the network first. To do that, you will use a Solidity compiler for node.js called solc. You can install it by running:

npm install -g solc

Create a file called MyToken.sol, and paste the contract code into it. Then, open a terminal console in the same dir where you placed that file. First, compile it running the following command:

solcjs MyToken.sol --bin

The compiler will create a MyToken_sol_MyToken.bin file with the output. You can check that file contains just bytecode. Next, you will need to use solc to build the ABI (Application Binary Interface), an interface or template of your contract that tells you the available methods of it. This is the point of contact with Web3. Your just need to run:

solcjs MyToken.sol --abi

Then, you will see a new file called MyToken_sol_MyToken.abi with a JSON content that bassically defines the interface of your contract.

Finally you just need to deploy your contract from a node.js console using testrpc running in background. Once you have done that, let’s initialize web3:

//instance web3
Web3 = require('web3')
provider = new Web3.providers.HttpProvider("http://localhost:8545")
web3 = new Web3(provider)

Web3 gives you the possibility to parse your contract ABI and provide a JavaScript API to interact with it. Then, you just need the bytecode to deploy a new instance of that contract to testrpc. Please follow the next commands:

// load files
myTokenABIFile = fs.readFileSync('MyToken_sol_MyToken.abi')
myTokenABI = JSON.parse(myTokenABIFile.toString())
myTokenBINFile = fs.readFileSync('MyToken_sol_MyToken.bin')
myTokenByteCode = myTokenBINFile.toString()
//deploy
account = web3.eth.accounts[0]
MyTokenContract = web3.eth.contract(myTokenABI)
contractData = { data: myTokenByteCode, from: account, gas: 999999 }
deployedContract = MyTokenContract.new(contractData)

Finally, you can check the address of your new deployed contract by calling deployedContract.address. Please save that address because you will need it to interact with your contract 😃


2.4. Web3 and smart contracts

Let’s begin by searching the token balances of your testrpc accounts. To do so, you will need to access the instance of your deployed contract first:

contractAddress = deployedContract.address
instance = MyTokenContract.at(contractAddress)
web3.eth.accounts.forEach(address => {
tokens = instance.balanceOf.call(address)
console.log(address + ": " + tokens)
})

You will notice that your first account is the one that owns the total supply, which is expected. Great! Next, let’s transfer some of those tokens to another account:

// send tokens
amount = 10
from = web3.eth.accounts[0]
to = web3.eth.accounts[1]
transactionHash = instance.sendTokens(to, amount, { from: from })
// checkout balances again
web3.eth.accounts.forEach(address => {
tokens = instance.balanceOf.call(address)
console.log(address + ": " + tokens)
})

You should see that now the second address has 10 tokens! And you can also search for the transaction information as you did in the first part of this guide:

web3.eth.getTransaction(transactionHash)

I also built a simple UI for this mini DApp, you can find it here. You will see a MyToken.json file that holds the ABI of our contract. I just pasted the content of the ABI generated by the solidity compiler into it. You will also find an app.js file similar to the previous app, but including the logic that I just showed you to send tokens and detailed token balances of your accounts.

UI of the DApp that I built to test MyToken transfers

You can download this app too and start playing with it. You will be asked for the address of the contract instance that you deployed.

=======================================================

This is the third part of our Ethereum introduction guide. If you haven’t read parts 1 and 2

Index

1. Taking the first steps

2. Interacting with a contract

3. Frameworks & Tools in the real world

3.1. Deploying with Truffle

3.2. Testing smart contracts

3.3. OpenZeppelin

4. A real DApp, a token marketplace — coming soon


3. Frameworks & Tools in the real world

As you may have noticed, most of the work that we’ve been doing was pretty manual. Although this is a young industry, there are some tools that will make development easier. Let’s see some of them.

3.1. Deploying with Truffle

Until now, the only way we used to interact with our contracts was to deploy them manually through a Node console into a testrpc node and then load them using Web3. Now, let me introduce Truffle to you. It is an Ethereum development framework that will help us debugging, deploying, and testing smart contracts, among other things.

The first thing we’re going to do is to deploy a contract using Truffle. Let's create a new directory for this exercise and run the following commands to install Truffle and initialize our project:

$ mkdir truffle-experiment
$ cd truffle-experiment/
$ npm install truffle@4.0.4
$ npx truffle init

You will see some folders and files were created. Our directory should look like:

truffle-experiment/
├── contracts/
│ └── Migrations.sol
├── migrations/
│ └── 1_initial_migration.js
├── test/
├── truffle.js
└── truffle-config.js

The contracts folder is where the smart contracts should be. The migrations folder will host javascript files that will help us deploying our contracts to the network. You may also have seen a Migrations contract in the first folder, this is where the history of our migrations is going to be stored on-chain. The test folder is initially empty and is intended to keep our test files. Finally, you will see a truffle.js and a truffle-config.js files. We will skip them by now, but you can read more in their documentation.

Now, let’s leave that boring stuff behind and focus on the interesting parts. To see an example of how we can deploy a contract using Truffle, we can use the same token contract example from the previous post of this guide. Please grab that code and paste it into a MyToken.sol file inside the contracts folder. Then, create a new migration file called 2_deploy_my_token.js file and copy the following lines into it:

const MyToken = artifacts.require('./MyToken.sol')
module.exports = function(deployer) {
deployer.deploy(MyToken)
}

As you can see, that migration will just deploy our token to the network. This time, we won’t need a testrpc node running since Truffle already comes with a simulation node for development and testing purposes. We just need to open a development console running npx truffle develop and run the migrations using truffle migrate inside it. Then, you should see an output like this:

truffle(develop)> truffle migrate
Using network ‘develop’.
Running migration: 1_initial_migration.js
Deploying Migrations…
… 0xf5776c9f32a9b5b7600d88a6a24b0ef433f559c31aaeb5eaf6e2fc5e2f7fa669
Migrations: 0x8cdaf0cd259887258bc13a92c0a6da92698644c0
Saving successful migration to network…
… 0xd7bc86d31bee32fa3988f1c1eabce403a1b5d570340a3a9cdba53a472ee8c956
Saving artifacts…
Running migration: 2_deploy_my_token.js
Deploying MyToken…
… 0xc74019c2fe3b3ef1d4e2033c2e4b9fa13611f3150f8b6b37334a8e29e24b056c
MyToken: 0x345ca3e014aaf5dca488057592ee47305d9b3e10
Saving successful migration to network…
… 0xf36163615f41ef7ed8f4a8f192149a0bf633fe1a2398ce001bf44c43dc7bdda0
Saving artifacts…

We’ll just care about the line MyToken: 0x345ca3e0...305d9b3e10, which tells us the address of our deployed token contract. By default, Truffle initializes the simulation node with 10 addresses with fake ETH as we saw when using testrpc, and we can access this array via web3.eth.accounts. Moreover, it deploys these contracts using the first address of this list (the one with index 0), which means that it will be the owner of MyToken.

Given that Web3 is available inside the Truffle console, you can just run the following commands to check the owner’s balance:

truffle(develop)> owner = web3.eth.accounts[0]
truffle(develop)> instance = MyToken.at('[DEPLOYED_ADDRESS]')
truffle(develop)> instance.balanceOf(owner)

Note: Please remember to replace [DEPLOYED_ADDRESS] by the address of the deployed contract given by Truffle, in this case: 0x345ca3e0...305d9b3e10.

We can also send some tokens to another address and then check the updated balances:

// send tokens
amount = 10
recipient = web3.eth.accounts[1]
txHash = instance.sendTokens(recipient, amount, { from: owner })
// check balances
instance.balanceOf(owner)
instance.balanceOf(recipient)

We’ve seen the recipient account now has 10 tokens! We can search the transaction information with the following line of code:

web3.eth.getTransaction(txHash)

3.2. Testing smart contracts

The next more interesting and useful thing about Truffle is that we can test our contracts. This framework lets you write tests in two different ways: Javascript and Solidity. In this post, we will just learn some basics about JS tests, which is the most used option.

Truffle uses Mocha under the hood as the testing framework and Chai to perform assertions. It doesn’t matter if you are not familiar with these libraries, both are really straightforward and implement a similar syntax to other testing frameworks. You can also read the official Mocha documentationif you want.

That said, let’s start with our first test case. We’ll need to create a MyToken.jsfile inside the test folder. Once you have done that, please paste the next chunk of code into it:

const MyToken = artifacts.require('MyToken')
contract('MyToken', accounts => {
  it('has a total supply and a creator', async function () {
const owner = accounts[0]
const myToken = await MyToken.new({ from: owner })
    const creator = await myToken.creator()
const totalSupply = await myToken.totalSupply()
    assert(creator === owner)
assert(totalSupply.eq(10000))
})
})

To run Truffle tests you just need to use the command npx truffle test. Again, there is no need to have running a rpc test node in background since Truffle will do that for you.

As you may have noticed, this is the second time we use artifacts.require()in our code. The first time was to write the MyToken migration, and by now you might be wondering what it means. Artifacts are the result of compiling every contract separately. These will be placed in the build/contracts/directory relative to your project root. Through artifacts.require() is how we tell Truffle which contract we’d like to interact with. Just provide the name of a contract and get an abstraction to use it. You can read more about Truffle artifacts here.

The only important thing left is the contract() function, which is really similar to Mocha’s describe() function. This is how Truffle guarantees a clean-room environment, it will redeploy your contracts to your Ethereum client and provide a list of the available accounts in it every time it gets called. We do not recommend using deployed instances of contracts for tests, though. It’s better to have each test manage their own instances.

Now that we know some basics about testing with Truffle, let’s add another interesting scenario. We will test token transfers between accounts:

it('allows token transfers', async function () {
const owner = accounts[0]
const recipient = accounts[1]
const myToken = await MyToken.new({ from: owner })
  await myToken.sendTokens(recipient, 10, { from: owner })
  const ownerBalance = await myToken.balanceOf(owner)
assert(ownerBalance.eq(9990))
const recipientBalance = await myToken.balanceOf(recipient)
assert(recipientBalance.eq(10))
})

Finally, it would be good to add some other edge cases, but I will leave that to you. You can also see how I finished this mini DApp using Truffle with the rest of the test cases here. You’ll see that I just tackled the same features as we did for the app in the previous post. The only thing that changed is that we’re using Truffle to launch a testing node, deploy our contract and add some tests to make sure our contract works the way we expected.


3.3. OpenZeppelin

If you got here I’m almost sure you’ve heard about OpenZeppelin. If you haven’t, you just need to know that it is the most used framework that helps you build smart contracts. It is an open-source framework that provides reusable smart contracts to build distributed applications, protocols and organizations, reducing the risk of vulnerabilities by using standard, tested and community-reviewed code.

Given the huge amount of token contracts, the Ethereum community created a token standard called ERC20 two years ago. The idea was to allow DApps and wallets to handle tokens across multiple interfaces and DApps in a common way.

That said, it is understandable that some of the most used OpenZeppelin contracts are ERC20 implementations. And this is what we are going to do with our MyToken contract as a first step: make it ERC20 compliant. Let’s install the OpenZeppelin framework first, to do so we will need to run:

$ npm install zeppelin-solidity

Now, take a look at the new implementation we built using some of OpenZeppelin’s contracts:

import 'zeppelin-solidity/contracts/token/BasicToken.sol';
import 'zeppelin-solidity/contracts/ownership/Ownable.sol';
contract MyToken is BasicToken, Ownable {
  uint256 public constant INITIAL_SUPPLY = 10000;
  function MyToken() {
totalSupply = INITIAL_SUPPLY;
balances[msg.sender] = INITIAL_SUPPLY;
}
}

As you can see we have removed a lot of core functionality. Well, we haven’t removed it, we are just delegating that behavior to the OpenZeppelin contracts. This is really useful since we’re reusing secured and audited code, meaning that we have reduced the attack surface of our contracts.

Moreover, you may have noticed that we’re extending our token contract from two OpenZeppelin contracts: Ownable and BasicToken. Yes, Solidity supports multiple inheritance, and it is really important for you to know that order matters. Unfortunately this is out of the scope of this post, but you can learn more about it here.

As we said, we are extending MyToken from Ownable. Let’s take a look at this contract:

contract Ownable {
address public owner;
event OwnershipTransferred(address indexed previousOwner, address indexed newOwner);
function Ownable() public {
owner = msg.sender;
}
modifier onlyOwner() {
require(msg.sender == owner);
_;
}
function transferOwnership(address newOwner) public onlyOwner {
require(newOwner != address(0));
OwnershipTransferred(owner, newOwner);
owner = newOwner;
}
}
OpenZeppelin Ownable contract

Ownable provides three main functionalities:

  • It holds a special address we’ll call its "owner",
  • It allows us to transfer the ownership of a contract, and
  • It provides a useful onlyOwner modifier that will guarantee that a function can only be called by the owner.

Pretty useful, isn’t it? On the other hand, we are extending the BasicTokencontract too. Let’s see how that one works:

import '../math/SafeMath.sol';

contract ERC20Basic {

  uint256 public totalSupply;

  function balanceOf(address who) public view returns (uint256);

  function transfer(address to, uint256 value) public returns (bool);

  event Transfer(address indexed from, address indexed to, uint256 value);

}

contract BasicToken is ERC20Basic {

  using SafeMath for uint256;

  mapping(address => uint256) balances;

  function transfer(address _to, uint256 _value) public returns (bool) {

    require(_to != address(0));

    require(_value <= balances[msg.sender]);

    balances[msg.sender] = balances[msg.sender].sub(_value);

    balances[_to] = balances[_to].add(_value);

    Transfer(msg.sender, _to, _value);

    return true;

  }

  function balanceOf(address _owner) public view returns (uint256 balance) {

    return balances[_owner];

  }

}

OpenZeppelin BasicToken contract

I’m sure you are more familiar with this code. It is basically what we were doing inside MyToken contract. There are some minor differences because we were not following the ERC20 standard in the original version. What we called sendTokens here it is just transfer, which implements pretty much the same behaviour besides triggering the Transfer event.

Another important thing is the using SafeMath for uint256 line. SafeMath is a library proposed by OpenZeppelin to do mathematical operations with safety checks. This is another of the most used contracts since it guarantees that math operations don’t overflow.

OpenZeppelin is a whole world in itself, please take the time to analyze and learn it deeply. You can start by reading and paying careful attention to the security details of the audited and reviewed codebase.


We have learned two amazing tools of the Ethereum world that will definitely make your development easier. Truffle will help you testing and deploying, and OpenZeppelin will help you writing secure smart contracts through an audited codebase.

Comments