Creating a Token Smart Contracts for the Blockchain Part 3
Now that we have the basic implementation of the ERC-20 token created, let's create a few smart contracts that we can use to add more functionality to the token smart contract we will be creating. At the end of this chapter, we will be ready to compile and deploy our token smart contract.
In the last chapter we created the ERC20.sol
smart contract. This file imported the libraries and interface that we created and has all of the requirements of the ERC-20 token standard.
Let's take another look at the smart contracts that are required to write the token smart contract for this book once again.
As per the ERC-20 Token Standard:
Interfaces:
IERC20.sol // necessary
Libraries:
SafeMath.sol // necessary
Context.sol // necessary
Role.sol // plays a role with ERC20Mintable.sol
MinterRole.sol // plays a role with ERC20Mintable.sol
Contracts:
ERC20.sol // necessary
ERC20Detailed.sol // introduces additional capabilities
ERC20Burnable.sol // introduces additional capabilities
ERC20Mintable.sol // introduces additional capabilities
Contracts we will deploy:
ERC20Combined.sol // combines everything together
In this chapter, we will be adding additional functionality to our ERC-20 token smart contract with the ERC20Detailed.sol
, ERC20Burnable.sol
, and ERC20Mintable.sol
smart contracts. Once we write the contracts mentioned, we will combined it all together with ERC20Combined.sol
.
In addition to the contracts mentioned, we will also need to introduce a few more libraries so that the ERC20Mintable.sol
smart contract works as desired.
ERC20Detailed.sol#
This contract implements the optional parameters of an ERC-20 token, including name
, symbol
and decimals
.
To kick things off, let's create the contract declaration in a new file called ERC20Detailed.sol
(in your /contracts
folder). We will have to import the interface IERC20.sol
because we want to ensure that contracts that inherit the ERC20Detailed
contract also implement the methods in IERC20.sol
.
pragma solidity ^0.5.0;
import "./IERC20.sol";
contract ERC20Detailed is IERC20.sol {
}
Within the contract brackets we need to create three private variables name
, symbol
and decimals
, and three public methods to read them.
// Variables
string private _name;
string private _symbol;
uint8 private _decimals;
// Methods to read the details of this token
function name() public view returns (string memory) {
return _name;
}
function symbol() public view returns (string memory) {
return _symbol;
}
function decimals() public view returns (uint8) {
return _decimals;
}
A few notes on the decimals
method:
Solidity can't handle decimals and performs all math required using fixed-point numbers
if
decimals
is equal to 2, a balance of 505 tokens should be displayed to the user as 505 / 10 ** 2tokens usually use a value of 18 for
decimals
because it follows the relationship between wei and ether (1 ** 18 wei = 1 ether)this is for display purposes only - does not affect the math of the contract (e.g. balanceOf, transfer, etc.)
The last thing we need for this contract is a constructor
method, to initialize the variables we just created. It will take in two string values and a uint8 value so that we can update the variables that we are tracking in this contract. This method will run whenever the contract is deployed. Upon deploying, we will need to pass in the name, symbol, and decimals we want for this token.
constructor(string memory name, string memory symbol, uint8 decimals) public {
_name = name;
_symbol = symbol;
_decimals = decimals;
}
Typically, constructors should be placed before the other methods of the smart contract so our final ERC20Detailed.sol
contract will look like this:
pragma solidity ^0.5.0;
import "./IERC20.sol";
contract ERC20Detailed is IERC20 {
string private _name;
string private _symbol;
uint8 private _decimals;
constructor(
string memory name,
string memory symbol,
uint8 decimals
) public {
_name = name;
_symbol = symbol;
_decimals = decimals;
}
function name() public view returns (string memory) {
return _name;
}
function symbol() public view returns (string memory) {
return _symbol;
}
function decimals() public view returns (uint8) {
return _decimals;
}
}
ERC20Burnable.sol#
This will be a simple smart contract that will be used to burn (destroy) tokens. The contract will be inherited by the main token contract that we will create at the end of the chapter. To kick things off, create a file in the contracts
folder called ERC20Burnable.sol
.
This is an extension of an ERC-20 token which will allow token holders to destroy their own tokens. The user will use a public smart contract method that we define here to destroy their tokens. The requirements of this method are as follows:
the
_burn
method is declared inERC20.sol
where it carries out a requirements check, so we just have to call it herethe function needs to import
ERC20.sol
to ensure that we have access to the_burn
method
Our contract will look something like this:
pragma solidity ^0.5.0;
import "./Context.sol";
import "./ERC20.sol";
contract ERC20Burnable is Context, ERC20 {
function burn(uint256 amount) public {
_burn(_msgSender(), amount);
}
}
Nice and simple! Now let's look at the opposite requirement - creating tokens with a contract called ERC20Mintable.sol
.
ERC20Mintable.sol#
The difference between a library and a contract in Solidity is that a library is a type of contract and the library contract does not have any storage (no variables allowed) and cannot hold any ether.
This will be a smart contract that will be used to mint (create) tokens. The contract will be inherited by the main token contract that we will create at the end of the chapter. Before we create the ERC20Mintable.sol
smart contract, there are a few things we need to create first.
Library:
Role.sol
Contract:
MinterRole.sol
Contract:
ERC20Mintable.sol
This page is a preview of Creating an ERC20 Token on Ethereum