This is our second Solidity tutorial, if you missed it take a look at our Introduction to Solidity where we walk you through some basics of this programming language for the Ethereum blockchain.
We explain a little about how Solidity works, how it’s structured and start you off with some simple code for writing a “Hello World” smart contract.
In this tutorial we go into more depth and teach you the code to deploy your own Ethereum ERC-20 token. ( Here’s our Blockonomi Token ).
Ethereum & The ICO Boom
ICO stands for Initial Coin Offering and it is a type of funding using cryptocurrencies. In an ICO, a quantity of cryptocurrency is sold in the form of “tokens” (“coins”) to speculators or investors, in exchange for legal tender or other cryptocurrencies such as Bitcoin or Ethereum.
The tokens sold are promoted as future functional units of currency if or when the ICO’s funding goal is met and the project launches.
We talked already how Smart contracts opened a whole new world for developers to create and innovate. However, these developers needed a way to finance their projects.
And the solution was the ICO.
In 2017 ICOs were booming – countless projects appeared every day with wild promises of what they wanted to achieve, and investors lapped them up.
Since then, things have calmed down as the space has matured and the investors have disappeared, many ICOs failed to deliver on what was promised, but that’s a story for another post – we’re here to discuss the technical side.
What is a Token?
Tokens are essentially smart contracts which live on the Ethereum Blockchain, they can have may uses and purposes.
A token is not limited to one particular role. It can fulfill a lot of roles in its native ecosystem. Here’s the list of some roles that tokens can take.
- Toll: A token can act as a gateway to a Dapp. Basically, in order to access the Dapp, you will need to hold the tokens.
- Voting Rights: The tokens may also qualify the holders to have certain voting rights. Think of EOS, holding EOS tokens will allow you to vote for block producers. EOS Blockchain is aiming to become a decentralized operating system which can support industrial-scale decentralized applications.
- Value Exchange: This is one of the more common roles of tokens within the ecosystem. Tokens can help create an internal economic system within the application.
- User Experience Enhancement: The token can also enable the holders to enrich the user experience inside the confines of the particular environment. Eg. In Brave (a web browser), holders of BAT (tokens used in Brave) will get the rights to enrich customer experience by using their tokens to add advertisements or other attention based services on the Brave platform.
- Currency: Can be used as a store of value which can be used to conduct transactions both inside and outside the given ecosystem.
What is ERC-20?
ERC-20 is a technical standard used for smart contracts on the Ethereum blockchain for implementing tokens. The majority of tokens issued on the Ethereum blockchain are ERC-20 compliant.
ERC-20 is a protocol standard that defines certain rules and standards for issuing tokens on Ethereum’s network. In ‘ERC-20’, ERC stands for Ethereum Request For Comments and 20 stands for a unique ID number to distinguish this standard from others.
To keep it simple, ERC-20 is a guide of rules and regulations that will help create a blueprint for Ethereum-based smart contracts to create their tokens.
A token on Ethereum is basically just a smart contract that follows some common rules — namely it implements a standard set of functions that all other token contracts share, such as transferFrom(address _from, address _to, uint256 _tokenId) and balanceOf(address _owner).
So basically a token is just a contract that keeps track of who owns how much of that token, and some functions so those users can transfer their tokens to other addresses.
Why ERC-20 Standard is so important?
Since all ERC-20 tokens share the same set of functions with the same names, they can all be interacted with in the same ways.
This means if you build an application that is capable of interacting with one ERC-20 token, it’s also capable of interacting with any ERC-20 token. That way more tokens can easily be added to your app in the future without needing to be custom coded. You could simply plug in the new token contract address, and boom, your app has another token it can use.
One example of this would be an exchange. When an exchange adds a new ERC-20 token, really it just needs to add another smart contract it talks to. Users can tell that contract to send tokens to the exchange’s wallet address, and the exchange can tell the contract to send the tokens back out to users when they request a withdraw.
The exchange only needs to implement this transfer logic once, then when it wants to add a new ERC-20 token, it’s simply a matter of adding the new contract address to its database.
Let’s Get Started Creating a Token
We will use Remix IDE for developing Smart Contract for our ERC-20 token.
Remix is online tool that allows you to write Solidity smart contract, then deploy it and run it.
Just go to https://remix.ethereum.org from your browser and we can start coding.
Click the Solidity button, and then the Plus button in upper left corner.
I will name it “BlockonomiToken”, you can choose whatever name you like for your own cryptocurrency.
Nice, everything is setup now.
ERC-20 Token Rules
ERC-20 tokens follow a list of rules so that they can be shared, exchanged for other tokens, or transferred to a crypto-wallet.
The ERC20 standard consists of 3 optional rules and 6 mandatory rules.
To put it in layman terms, if you include certain functions in the token’s smart contract, you are ERC20 compliant. If you don’t include the mandatory functions, you are not ERC20.
The mandatory rules are as follows:
- totalSupply
- balanceOf
- transfer
- transferFrom
- approve
- allowance
On the other hand, the optional rules are:
- Token Name
- Symbol
- Decimal (up to 18)
It is common practice to define these rules in the interface. There’s not really something called interface in Solidity, it’s just another Smart Contract. Luckily, one can inherit Smart Contracts in Solidity programming language.
Inheritance in Solidity
In Solidity, inheritance is pretty similar to classic oriented object programming languages. You’ll first write your base contract and tell that your new contract will inherit from the base one.
contract IBank {
// base contract code...
}
contract Bank is IBank {
// inherited contract code...
}
You also need to know that Solidity supports multiple inheritance by copying code including polymorphism.
All function calls are virtual, which means that the most derived function is called, except when the contract name is explicitly given.
When a contract inherits from multiple contracts, only a single contract is created on the blockchain, and the code from all the base contracts is copied into the created contract.
Let’s go back to our ERC-20 token. We have mandatory rules in order to create the ERC-20 token.
We will define them as 6 functions and write it in interface. Then our actually token’s contract will inherit that so call interface.
Your code will need to look like this.
contract ERC20Interface {
function totalSupply()
public
view
returns (uint);
function balanceOf(address tokenOwner)
public
view
returns (uint balance);
function allowance
(address tokenOwner, address spender)
public
view
returns (uint remaining);
function transfer(address to, uint tokens) public
returns (bool success);
function approve(address spender, uint tokens) public
returns (bool success);
function transferFrom
(address from, address to, uint tokens) public
returns (bool success);
event Transfer(address indexed from, address indexed to, uint tokens);
event Approval(address indexed tokenOwner, address indexed spender, uint tokens);
}
Token Contract
Let’s create our token contract. Type contract <Name_of_token> {}
Now we will go through 3 optional rules.
Even though it is not necessary to name your tokens, it is still important to give it an identity.
Up next we have symbols. We simply cannot understate their importance. A catchy symbol helps with better branding.
Finally, we have the divisibility which will help us determine the lowest possible value of the token. A divisibility of 0 will mean that the lowest value of the token is 1. A divisibility of 2, on the other hand, means its lowest value will be 0.01. The maximum number of decimal places allowed is 18. 18 decimals is the strongly suggested default, avoid changing it
Let’s define them and initialize in constructor.
contract BlockonomiToken is ERC20Interface {
string public name;
string public symbol;
uint8 public decimals;
constructor() public {
name = "BlockonomiToken";
symbol = "BKM";
decimals = 18;
}
}
Our token also needs to have an initial supply, and some record of all balances. We can store that information in array.
In constructor we will initialize our contract with initial supply tokens to the creator of the contract (that is msg.sender). Add these lines to our code and we will discuss purpose of all of them.
contract BlockonomiToken is ERC20Interface {
string public name;
string public symbol;
uint8 public decimals;
uint256 public _totalSupply;
mapping(address => uint) balances;
mapping(address => mapping(address => uint)) allowed;
constructor() public {
name = "BlockonomiToken";
symbol = "BKM";
decimals = 18;
_totalSupply = 100000000000000000000000000;
balances[msg.sender] = _totalSupply;
emit Transfer(address(0), msg.sender, _totalSupply);
}
}
Solidity Data Types
As you can see _totalSupply has a uint256 datatype and decimals uint8.
Solidity is a statically typed language, which means that the type of each variable (state and local) needs to be specified at compile-time. Solidity provides several elementary types which can be combined to form complex types.
Let’s discuss about Integers type for now.
Integers can be int or uint: Signed and unsigned integers of various sizes. If you are familiar with Computer Science theory or you know the difference between signed and unsigned integers in C language, everything is absolutely the same in Solidity.
If you’re not, we can just say that an unsigned is an integer that can never be negative! Signed on the other hand can be both negative and positive, but we will use only units in our contract.
Keywords uint8 to uint256 in steps of 8 (unsigned of 8 up to 256 bits) and int8 to int256. uint and int are aliases for uint256 and int256, respectively.
We talked that we will store balances in some kind of array. Well, the better solution is to use hash tables, or in Solidity mappings.
Basically we map address (that’s datatype also) to uint.
msg.sender (address): sender of the message (current call)
msg.sender will be the person who currently connecting with the contract.
Later on, you’ll probably deal with contracts connecting with contracts. In that case, the contract that is creating the call would be the msg.sender.
Mappings
Mapping types are declared as mapping(_KeyType => _ValueType). Here _KeyType can be almost any type except for a mapping, a dynamically sized array, a contract, an enum and a struct. _ValueType can actually be any type, including mappings.
Mappings can be seen as hash tables which are virtually initialized such that every possible key exists and is mapped to a value whose byte-representation is all zeros: a type’s default value. The similarity ends here, though: The key data is not actually stored in a mapping, only its keccak256 hash used to look up the value.
Because of this, mappings do not have a length or a concept of a key or value being “set”.
Mappings are only allowed for state variables (or as storage reference types in internal functions).
It is possible to mark mappings public and have Solidity create a getter. The _KeyType will become a required parameter for the getter and it will return _ValueType.
The _ValueType can be a mapping too. The getter will have one parameter for each _KeyType, recursively.
Events
The blockchain is a list of blocks which are fundamentally lists of transactions. Each transaction has an attached receipt which contains zero or more log entries. Log entries represent the result of events having fired from a smart contract.
In the Solidity source code, to define an event, you mark it thus by preceding it with the event keyword (similar in usage to the function keyword). Y
ou then call or fire the event in the body of whatever function you wish to cause to generate the event. (I doubt there is a standard wording for it). You may fire events from any function using the emit keyword.
ERC-20 Interface
Let’s implement ERC-20 Interface now. To do that, we need to write code for all of our six mandatory functions.
1. totalSupply
Identifies the total number of ERC-20 tokens created. The purpose of this method is to determine the total number of tokens floating around the ecosystem.
function totalSupply()
public
view
returns (uint)
{
return _totalSupply - balances[address(0)];
}
2. balanceOf
Returns the number of tokens that a particular address, in this case, the contract owner, has in their account.
function balanceOf(address tokenOwner)
public
view
returns (uint balance)
{
return balances[tokenOwner];
}
3. allowance
In order to carry out a transaction one of the most important data that the contract should know is the balance of the user. After all, the user should have the minimum amount of tokens required to do the transaction.
This is why, the ERC-20 contract also includes the allowance() function. If the user doesn’t have the minimum required number of tokens, the function cancels the transaction.
function allowance
(address tokenOwner, address spender)
public
view
returns (uint remaining)
{
return allowed[tokenOwner][spender];
}
4. approve
Once the balance has been checked, the contract owner can give their approval to the user to collect the required number of tokens from the contract’s address.
The approve function also checks the transaction against the total supply of tokens to make sure that there are none missing or extra.
In other words, it makes sure that counterfeiting is impossible.
function approve(address spender, uint tokens) public
returns
(bool success)
{
allowed[msg.sender][spender] = tokens;
emit Approval(msg.sender, spender, tokens);
return true;}
Safe Math Library
In order to correctly implements two remaining functions we need Safe Math Library.
Safe Math Library wrappers over Solidity’s arithmetic operations with added overflow checks.
Arithmetic operations in Solidity wrap on overflow. This can easily result in bugs, because programmers usually assume that an overflow raises an error, which is the standard behavior in high level programming languages.
Safe Math restores this intuition by reverting the transaction when an operation overflows.
Using this library instead of the unchecked operations eliminates an entire class of bugs, so it’s recommended to use it always.
All we need to do now is to copy this code above our contract, and then inherit it.
contract SafeMath {
function safeAdd(uint a, uint b) public pure returns (uint c) {
c = a + b;
require(c >= a);
}
function safeSub(uint a, uint b) public pure returns (uint c) {
require(b <= a); c = a - b; } function safeMul(uint a, uint b) public pure returns (uint c) { c = a * b; require(a == 0 || c / a == b); } function safeDiv(uint a, uint b) public pure returns (uint c) { require(b > 0);
c = a / b;
}
}
Don’t forget to inherit it.
contract BlockonomiToken is ERC20Interface, SafeMath
5. transfer
So, now that all the checking has been done and the contract knows that the user has the required amount of tokens needed to fulfill the transaction, the contract owner can send them tokens using the transfer() function.
This function lets the owner of the contract send a given amount of the token to another address just like a conventional cryptocurrency transaction., allows a certain number of tokens to be transferred from the total supply to a user account.
function transfer(address to, uint tokens)
public
returns (bool success)
{
balances[msg.sender] = safeSub(balances[msg.sender], tokens);
balances[to] = safeAdd(balances[to], tokens);
emit Transfer(msg.sender, to, tokens);
return true;
}
6. transferFrom
We have already covered the transfer function, why do we have another?
Well, let’s take an example to see why transferFrom is such a brilliant addition to the ERC20 contract.
We all have to pay some amount of money every month like clockwork. It could be your rent, the bills, etc. You don’t really need to pay all these amounts hands-on by yourself. You can always set up an automatic payment system with your banks to take care of these payments.
That’s what transferFrom() allows you to do. It helps you automate payment transfers to a specific account.
function transferFrom
(address from, address to, uint tokens)
public
returns (bool success)
{
balances[from] = safeSub(balances[from], tokens);
allowed[from][msg.sender] = safeSub(allowed[from][msg.sender], tokens);
balances[to] = safeAdd(balances[to], tokens);
emit Transfer(from, to, tokens);
return true;
}
The Full code
Here is the full code for our Blockonomi Token.
pragma solidity ^0.5.0;
// ----------------------------------------------------------------------------
// ERC Token Standard #20 Interface
//
// ----------------------------------------------------------------------------
contract ERC20Interface {
function totalSupply() public view returns (uint);
function balanceOf(address tokenOwner) public view returns (uint balance);
function allowance(address tokenOwner, address spender) public view returns (uint remaining);
function transfer(address to, uint tokens) public returns (bool success);
function approve(address spender, uint tokens) public returns (bool success);
function transferFrom(address from, address to, uint tokens) public returns (bool success);
event Transfer(address indexed from, address indexed to, uint tokens);
event Approval(address indexed tokenOwner, address indexed spender, uint tokens);
}
// ----------------------------------------------------------------------------
// Safe Math Library
// ----------------------------------------------------------------------------
contract SafeMath {
function safeAdd(uint a, uint b) public pure returns (uint c) {
c = a + b;
require(c >= a);
}
function safeSub(uint a, uint b) public pure returns (uint c) {
require(b <= a); c = a - b; } function safeMul(uint a, uint b) public pure returns (uint c) { c = a * b; require(a == 0 || c / a == b); } function safeDiv(uint a, uint b) public pure returns (uint c) { require(b > 0);
c = a / b;
}
}
contract BlockonomiToken is ERC20Interface, SafeMath {
string public name;
string public symbol;
uint8 public decimals; // 18 decimals is the strongly suggested default, avoid changing it
uint256 public _totalSupply;
mapping(address => uint) balances;
mapping(address => mapping(address => uint)) allowed;
/**
* Constrctor function
*
* Initializes contract with initial supply tokens to the creator of the contract
*/
constructor() public {
name = "BlockonomiToken";
symbol = "BKM";
decimals = 18;
_totalSupply = 100000000000000000000000000;
balances[msg.sender] = _totalSupply;
emit Transfer(address(0), msg.sender, _totalSupply);
}
function totalSupply() public view returns (uint) {
return _totalSupply - balances[address(0)];
}
function balanceOf(address tokenOwner) public view returns (uint balance) {
return balances[tokenOwner];
}
function allowance(address tokenOwner, address spender) public view returns (uint remaining) {
return allowed[tokenOwner][spender];
}
function approve(address spender, uint tokens) public returns (bool success) {
allowed[msg.sender][spender] = tokens;
emit Approval(msg.sender, spender, tokens);
return true;
}
function transfer(address to, uint tokens) public returns (bool success) {
balances[msg.sender] = safeSub(balances[msg.sender], tokens);
balances[to] = safeAdd(balances[to], tokens);
emit Transfer(msg.sender, to, tokens);
return true;
}
function transferFrom(address from, address to, uint tokens) public returns (bool success) {
balances[from] = safeSub(balances[from], tokens);
allowed[from][msg.sender] = safeSub(allowed[from][msg.sender], tokens);
balances[to] = safeAdd(balances[to], tokens);
emit Transfer(from, to, tokens);
return true;
}
}
Congratulations! You successfully developed your own ethereum token.
The last step is deployment to the actual network.
Deploying Your Token
To do this, we will need Metamask wallet.
Metamask is extension that allows you to run Ethereum dApps right in your browser without running a full Ethereum node.
Go to https://metamask.io/ from your browser ( Chrome, Firefox or Opera) and add it.
Create a New Wallet in MetaMask
When the extension is installed, click on the icon in the upper right corner of your browser to get started creating a wallet.
Read and accept the terms and then enter a strong password and click “Create”.
You will see a 12 words seed phrase. Save seed words as a file or copy them to a safe place and click “I’ve copied it somewhere safe”.
You have now successfully created an account in MetaMask with a new wallet address!
You will notice that currently you have 0 ETH in your wallet. To deploy contract on Ethereum network one need some amount of Ether. We will not deploy our contract to main network as this is just demo.
We will publish this contract to the test network. There’s a few Ethereum blockchain testnets actually – Ropsten, Rinkeby, Kovan …
Let’s use Ropsten for this example.
First you need some Ether, right? On test network we work with fake free ethers. One just need to claim some of those from Faucet.
Go to: https://faucet.ropsten.be/ , paste your wallet address and click “Send me test ether”.
After a couple seconds, you will see some ETH in your wallet.
Putting it Live
Now it’s time to make everything live!
Go to Remix IDE and compile the contract. If there’s no errors, we are ready for deployment.
For the environment select Injected Web3. It will automatically detect your metamask wallet.
Hit the Deploy button.
Metamask will now ask you to withdraw some funds from your wallet in order to purchase this transaction.
Confirm that. Then go back to Remix IDE, and pay attention to theTerminal. We see that the transaction has been successful.
We’ve got Transaction hash as result. Click on the uri from the terminal which looks like : ropsten.etherscan.io/<transaction_hash>
It will navigate us to etherscan.io – that’s Ethereum Blockchain explorer and here you can track everything that’s going on main and test networks, because everything is public on blockchain of course.
When we go to this uri we will see details about our transaction. Click on contract hash to explore more.
Everything is public on the blockchain, even our code. Solidity developers have no room for errors!
Click on the contract tab and you will see our compiled bytecode
Now you can go to Token Tracer to see details of our Blockonomi Token. You can see 3 optional rules that we defined earlier.
Now check your wallet. You will see that the Ether that we paid for deploying the smart contract on Ropsten has been removed.
Conclusion
That wraps up our tutorial, by following these steps and our code samples you should be able to deploy your own Ethereum ERC-20 Token.
Have fun!
2 Comments
Tokens created in ropsten test network CAN be used in “Real world” for ICO and exchanges? They can be moved to the mainnet? Or for “Real world” tokems must be createt in the eth mainnet only? Please answer… Thank you
nice article to read!