DEV Community

Jamiebones
Jamiebones

Posted on

ERC20 Token Standard

ERC stands for Ethereum Request for Comment used to initiate improvement proposals to the Ethereum blockchain in the hope of making them a standard. The ERC20 standard is a common one that is implemented for the creation of fungible tokens on the Ethereum blockchain. Fungible tokens refer to what can be broken down into smaller sub units (like money).

Tokens represent a store of value. The value attached to a token makes it economic viable as a means of exchange or worthless with no value.

Definition of Terminologies

Coin

A coin is a native digital asset or cryptocurrency of a blockchain. The Ethereum blockchain has the Ether with a symbol of ETH that is used for executing transactions in the blockchain. A coin is different from a token because it is the currency of a blockchain.

Token

A token is a digital asset or a cryptocurrency that is built on top of an existing blockchain. An example of a token is the DAO or Maker token which is built on the Ethereum blockchain with Solidity smart contract.

ERC20 Methods


function name() public view returns (string)
function symbol() public view returns (string)
function decimals() public view returns (uint8)
function totalSupply() public view returns (uint256)
function balanceOf(address _owner) public view returns (uint256 balance)
function transfer(address _to, uint256 _value) public returns (bool success)
function transferFrom(address _from, address _to, uint256 _value) public returns (bool success)
function approve(address _spender, uint256 _value) public returns (bool success)
function allowance(address _owner, address _spender) public view returns (uint256 remaining)
Enter fullscreen mode Exit fullscreen mode

ERC20 Events

event Transfer(address indexed _from, address indexed _to, uint256 _value)
event Approval(address indexed _owner, address indexed _spender, uint256 _value)
Enter fullscreen mode Exit fullscreen mode

To create a token that is ERC20 standard compliant, your token must implement some core functions from the interface. The core functions that must be implemented from the above list of functions are:

totalSupply()
balanceOf(account)
transfer(recipient, amount)
allowance(owner, spender)
approve(spender, amount)
transferFrom(sender, recipient, amount)
Enter fullscreen mode Exit fullscreen mode

These are the functions which must be implemented by your token so as to become compliant with the standard.

The optional functions of name() , symbol() and decimal() belong to another standard referred to as ERC20Detailed which sets the values of this three functions in the constructor function of the smart contract that creates the token.

constructor(name, symbol, decimals)

The ERC20Detailed standard provides some missing functionality from the ERC20 standard. When creating a token smart contract, it is not unusual to inherit from both two standards.

State Variables in ERC20 Standard

The following are the state variables described by the standard and their uses.

balances

This is a mapping that holds the amount of token credited to addresses.

  mapping(address => uint256) internal balances;
Enter fullscreen mode Exit fullscreen mode

The entry in the balances variable is updated when the
transferFrom() or transfer()functions are called. The balances state variable acts as an account ledger, that details who owns what amount of token.
To retrieve a value from the balances mapping, the function balanceOf() is called with the address of the account we want to read their balance from. The use of the mapping data structures makes this retrieval to happen in O(1) time, that is constant time.

allowed

The allowed state variable is defined in the contract as follows:

mapping(address => mapping (address => uint256 )) internal allowed;
Enter fullscreen mode Exit fullscreen mode

The allowed variable contains a mapping with an address as key to another mapping which contains an address mapped to a uint256. (nested mapping )

The allowed variable is used to store the amount of token that a token owner has approved to be spent on their behalf by another account. A token holder X can assign that a certain amount of token N, to another account Y, so that Y is allowed to take the approved N number of tokens from the token balance of X.

totalSupply

The totalSupply variable is defined as follows in a smart contract:

uint256 internal _totalSupply();
Enter fullscreen mode Exit fullscreen mode

This variable stores the total amount of the token that exist in circulation. The value of this variable is read by the function totalSupply().

Functions and Methods in the Standard

transfer

This function as the name specifies is used to transfer tokens from the owner to another address. The standards requires a Transfer event to be emitted on a successful transfer of token. When a transfer of token occurs, the balance of the token holder is reduced by the amount that was transferred while the receiver has it's balance in the balances variable increased by the transferred amount.

Implementation of the transfer function

function transfer(address _to, uint256 _value) public returns (bool) {
  //check if the person making the transfer have token more or equal to the value being transferred 
  require(_value <= balances[msg.sender]);
 balances[msg.sender] = balances[msg.sender].sub(_value);
 balances[_to] = balances[_to].add(_value);
 emit Transfer (msg.sender, _to, _value );
 return true;
}
Enter fullscreen mode Exit fullscreen mode

We are making use of the Safe Math Library methods of add and sub so as to prevent integer overflow or underflow since we are dealing with huge numbers.

The ERC20 standard transfer function should not be confused with the one (transfer function) used by smart contracts to transfer ether to an address.

sample code:

    address payable internal toAddress;
    address(toAddress).transfer(msg.value);
Enter fullscreen mode Exit fullscreen mode

approve

This function allows an address (owner) to approve another address (spender) to be able to spend tokens on behalf of the (owner) account. The owner approves a particular ** token amount** that the spender can withdraw on their behalf. This function is necessary to enable a third party to be able to withdraw approved token from an owner's address.

The ERC20 API specifies that the following signature for the approve function

 function approve(address _spender, uint256 _amount) external returns (bool success);
Enter fullscreen mode Exit fullscreen mode

The approve function returns a bool if the approval was successfully executed. An Approval event is also emitted on a successful execution.

Implementation of the approve function

 function approve(address _spender, uint256 _amountApproved) public returns (bool) {
  //remember the allowed state variable is used to store the approvals
 allowed[msg.sender][_spender] = _amountApproved;
 //broadcast to the blockchain about the approval
 emit Approval(msg.sender, _spender, _amountAllowed);
 return true;
}
Enter fullscreen mode Exit fullscreen mode

transferFrom

This function is used by an address to transfer funds from another address with prior approval. The transferFrom function accepts three parameters which are:

  • from : account the token is to be transferred from.
  • to : account the token will be transferred into.
  • amount : amount of token to transfer

Before an address can transfer token from another address, an approval must be given prior to the transfer. This means that the address which the token is transferred from must call the approve function to authorised the transfer of tokens.

Implementation of transferFrom function

function transferFrom(address _from, address _to, uint256 _amount )  public returns (bool ){
 //first check if the address to transfer from has that much token

require( amount <= balances[_from] );
//check if the address making the transfer has the allowance to do that
required(_amouunt <= allowed[_fromr][msg.sender]);
//prevent the transfer of this token to the grave yard which is the address(0) where nothing is recovered from
require(_to != address(0);
balances[_from] = balances[_from].sub(_amount);
balances[_to] = balances[_to].add(_amount);
//subtract the transfer value from the allowed variable
allowed[_from][msg.sender] = allowed[_from][msg.sender].sub(_amount);
emit Transfer(_from, _to, _amount);
return true
}
Enter fullscreen mode Exit fullscreen mode

msg.sender here refers to the address making the transfer

allowance

This function returns the amount of token that an address is allowed to spend on behalf of another address.

function allowance(address _owner, address _spender ) public view returns (uint256) {
  returns allowed[_owner][_spender];
}
Enter fullscreen mode Exit fullscreen mode

balanceOf function

This function returns the token balance of the given address. It retrieves the value from the balances state variable.

 function balanceOf(address _owner) public view returns (uint256) {
   return balances[_owner];
}
Enter fullscreen mode Exit fullscreen mode

totalSupply function

The totalSupply function reads the value of the _totalSupply state variable which holds the total number of token available in circulation. This value is updated when tokens are minted (created) or burn (destroyed)

 function totalSupply() public view returns (uint256) {
   return _totalSupply;
}
Enter fullscreen mode Exit fullscreen mode

Events

Two events are defined by the standards which are the Transfer event and the Approval event. These events can be listened to by a client who subscribes to them. Events are used to tell about happenings on the blockchain.

Signature of the Transfer event

event Transfer(address indexed from, address indexed to, uint256 value);
Enter fullscreen mode Exit fullscreen mode

Signature of the Approval event

event Approval(address indexed owner, address indexed spender, uint256 value);
Enter fullscreen mode Exit fullscreen mode

Summary

The ERC20 standard provides a way for fungible token to be uniform in their implementation so that they can be easily swapped with one another because if all token implements the same standard, it becomes easy and consistent to interact with them.

The examples given are for the reader to know what is happening underneath the hood. Instead of coding your token from scratch you can use the implementation of OpenZepplin and decide to overide any of the functions for your own implementationor. Their code has been tested, audited and it is being used by many.

pragma solidity ^0.5.0;

import "@openzeppelin/contracts/token/ERC20/ERC20.sol";
import "@openzeppelin/contracts/token/ERC20/ERC20Detailed.sol";

contract GLDToken is ERC20, ERC20Detailed {
    constructor(uint256 initialSupply) ERC20Detailed("Gold", "GLD", 18) public {
        _mint(msg.sender, initialSupply);
    }
}

Enter fullscreen mode Exit fullscreen mode

The above code does just that by creating a token called GLDToken.

I hope I was able to improve your understanding of the ERC20 token standard. Thanks for reading..

Happy coding!

Top comments (0)