ERC20 Introduction — Part 1

Dejan Jovanovic
TheBlockchainHub
Published in
10 min readDec 18, 2018

Introduction

What is ERC20 token and why do we need this? ERC stands for “Ethereum Request for Comment”. This is the Ethereum version of Request for Comments (RFC), a concept created by the Internet Engineering Task Force. It is used for capturing technical and organizational notes. In the case of ERC, this includes technical guidelines for the buildout of the Ethereum network.

So how does it works? Developers submit an Ethereum Improvement Proposal (EIP), this includes protocol specifications and contract standards. Once the Ethereum Committee finalizes and approves an EIP, it becomes and ERC.

Released and finalized EIPs are providing the Ethereum developers with a set of implementable standards. ERC-20 is one of the most well-known of all standards and most tokens issued on top of the Ethereum platform complies to it.

What is the ERC-20 Standard?

Originally ERC-20 was proposed back in 2015 and officially formalized in September 2017. It is a great starting point in token standardization. The ERC-20 token standard includes the following functions:

totalSupply() : returns total token supplybalanceOf(address _owner) : returns account balance of _owner’s accounttransfer(address _to, uint256 _value) : takes in number _value and transfers that amount of tokens to provided address _toand triggers transfer eventtransferFrom(address _from, address _to, unit256 _value) : transfer _value amount of tokens from the address _from to the address _to, and triggers the transfer eventapprove(address _spender, uint256 _value) : allows _spender to any number of tokens up to _value amountallowance(address _owner, address _spender) : returns amount which the _spender is allowed to withdraw from the _owner

The following events are triggered based on the listed ERC-20 functions:

transfer(address indexed _from, address indexed _to, uint256 _value) : this is triggered whenever tokens are transferredapproval(address indexed _owner, address indexed _spender, uint256 _value) : this is triggered on any call to approve() function

There are cases when additional functionality or improvements are needed, thus additionally to ERC-20 the following ERC standards are proposed:

ERC-223

ERC-223 proposal addresses the case when tokens are transferred to a smart contract. ERC-223 is backwards compatible with ERC-20 token. Status of this ERC is open and proposed on March 5, 2017.

There are two different ways to transfer ERC-20 tokens, depending on whether you intend to send the tokens directly to an account or delegate the transfer to another smart contract:

1. Invoking transfer() function

2. Or by invoking approve() function and then calling transferFrom() function

What happens when you transfer your tokens by mistake to a contract address that is unaware or doesn’t expect these tokens? The problem with invoking transfer() function is that a smart contract will not notify the recipient of the transfer of the transaction; therefore, he/she will not be able to recognize the incoming transaction. If you send for example 100 ERC20 tokens to a contract that is not intended to work with ERC20 tokens, the smart contract will not reject the transaction because it can’t recognize an incoming transaction request. As a result, your tokens will get stuck at the contracts balance.

When the recipient is a smart contract, users must transfer their tokens using the second option (approve() + transferFrom()). In the case that the recipient is a externally owned account address, the user must transfer their tokens using transfer() function. If user makes a mistake and chooses the wrong function, the token will be lost inside the smart contract.

There are already a number of tokens held by token contracts that did not expect any token transfer. These tokens are not accessible as there is no withdraw function available. Here are some examples:

310.067 GNT Stuck in Golem contract

242 REP Stuck in Augur contract

814 DGD Stuck in Digix DAO contract

14.506 1ST Stuck in FirstBlood contract

30 MLN Stuck in Melonport contract

The proposed solution, covered under ERC-223 is to use following for transfers of tokens to smart contract:

transfer(address _to, uint _value, bytes _data) returns (bool success)

This method is responsible for transferring tokens and invoking method:

tokenFallback(address _from, uint256 _value, bytes data)

This function will allow receiving contract to decline the token or trigger further actions. This can be used in place of the approve() function. Please see example:

contract ERC223ReceivingContract {/*** @dev Standard ERC223 function that will handle incoming token   
* transfers.
*
* @param _from Token sender address.
* @param _value Amount of tokens.
* @param _data Transaction metadata.
*/
function tokenFallback(address _from, uint _value, bytes _data);}
contract ERC223Token is ERC223Interface {
using SafeMath for uint;
mapping(address => uint) balances; // List of user balances.
/*** @dev Transfer the specified amount of tokens to the
* specified address.
* Invokes the `tokenFallback` function if the recipient is a
* contract.
* The token transfer fails if the recipient is a contract
* but does not implement the `tokenFallback` function
* or the fallback function to receive funds.
*
* @param _to Receiver address.
* @param _value Amount of tokens that will be transferred.
* @param _data Transaction metadata.
*/
function transfer(address _to, uint _value, bytes _data) {
// Standard function transfer similar to ERC20 transfer with no
// _data .
// Added due to backwards compatibility reasons .

uint codeLength;
assembly {
// Retrieve the size of the code on target address, this
// needs assembly .
codeLength := extcodesize(_to)
}
balances[msg.sender] = balances[msg.sender].sub(_value);
balances[_to] = balances[_to].add(_value);

if(codeLength>0) {
ERC223ReceivingContract receiver =
ERC223ReceivingContract(_to);
receiver.tokenFallback(msg.sender, _value, _data);
}
Transfer(msg.sender, _to, _value, _data);
}

}

Reference implementation available at: https://github.com/Dexaran/ERC223-token-standard/tree/master/token/ERC223

ERC-621

ERC-621 proposal addresses the case when tokens supply needs to be changed. Status of this ERC is open and proposed on May 1, 2017.

In order to address this need the proposition is to add the following functions to ERC-20 token:

increaseSupply(uint256 _value, address _to) : allows at any time to increase existing supply for specified addressdecreaseSupply(uint256 _value, address _from) : supply can be decreased at any time by specified _value for the owner _from

This proposal is mostly relevant to digitized assets management.

ERC-721

ERC-721 addresses totally different needs from what ERC-20 and ERC-223 are addressing. It describes a non-fungible token. Fungible is being something such as money or commodity of such nature that one part or quantity in paying a debt or settling an account according to the Merriam Webster dictionary. Fungibility is a characteristic of an asset or token. But if you are tracking collectables such as Pokemon cards where each card has it own characteristics (attributes) and potentially are different from each other from any perspective including price, then we are looking at a non-fungible token.

This means that each token is totally different and each one can have totally different values to different users. Each one is its own separate commodity whose values are based on its own rarity and desirability by users.

The standard definition of functions is:

name() constant returns (string name) : this function returns the name. Interfaces and other smart contracts must not depend on existence of this function.symbol() constant returns (string symbol) : this method returns the symbol referencing the entire collection of non fungible tokenstotalSupply() constant return (uint256 totalSupply) : returns the number of non fungible tokens currently tracked by the contractbalanceOf(address _owner) constant returns (uint256 balance) : returns the number of non fungible tokens assigned to address _ownerownerOf(uint256 _tokenId) constant returns (address owner) : this method returns the owner of _tokenIdapprove(address _to, uint256 _tokenId) : this method grants the approval of the address _to to take possession of the non fungible token _tokenId. Only one address can have approval at any given time, calling method approveTransfer with a new address revokes approval for the previous address. Successful completion of this method creates the Approve event.takeOwnership(uint256 _tokenId) : this function is responsible for assigning the ownership of the non fungible token to the message sender or it throws exception if message sender does not have approval for _tokenId, or _tokenId does not represent non fungible token currently tracked by the smart contract, or message sender already has ownership of the _tokenId.transfer(address _to, uint256 _tokenId) : this method assignees the ownership of the non fungible token with id that is _tokenId to _to if and only as message sender is also a owner of the token (msg.sender == ownerOf(tokenId)). A successful transfer must fire the Transfer event. In the case that transfer is not successful it will throw the exception. Exception is thrown in following cases: message sender is not a owner of _tokenId, or _tokenId does not represent currently tracked non fungible token, or _to is 0.tokenOfOwnerByIndex(address _owner, uint256 _index) constant return (uint tokenId) : this method is optional and it is recommended to be implemented in order to enhance usability with wallets and exchanges. It returns non fungible token that is assigned to the address of the _owner, with value of the _index argument. This method throws exception in the case that _index >= balanceOf(owner).tokenMetadata(uint256 _tokenId) constant returns (string infoUrl) : this method is optional but it is recommended to be implemented for enhanced usability with wallets and exchanges. This method returns multi address string referencing an external resource bundle that contains metadata about non fungible token associated with _tokenId. The string must be an IPFS of HTTP/HTTPS base path.

Following events are supported:

Transfer(address indexed _from, address indexed _to, uint256 _tokenId) — this event must be triggered when non fungible tokens ownership is transferred. Additionally in the case of creation of new non fungible token this event is triggered with _from address of 0 and a _to address matching the owner of new non fungible token, and also in the case of deletion event is triggered with _to address of 0 and a _from address of the owner.Approval(address indexed _owner, address indexed _approved, uint256 _tokenId) — this event is triggered on any successful call to approve(address _spender, uint256 _value)ApprovalForAll(address indexed _owner, address indexed _operator, bool _approved) - this event is emit when operator is disabler or enabled for an owner

Following table presents the cases when Approve event is triggered:

ERC-827

ERC-827 presents another extension to ERC-20, and it allows for the transfer of tokens and also allows tokens to be approved by the holder in order to be spent by a third party. It can be used to solve the same problem that ERC-223 is resolving, preventing ERC-20 tokens to be stuck. Moreover, it offers flexibility to transfer data along with tokens to smart contract and execute them. ERC-827 has been included in Zeppelin open source contract. On Ethereum blockchain tokens can be reused by other applications from wallets to decentralized exchanges.

To understand ERC-827 token let’s go through a shopping cart example.

Let say that a shopping cart has items waiting to be bought. In order to complete the transaction the user has to transfer tokens to the shopping cart with some data passed with the cart which will call another smart contract that is responsible for checking whether the cart owner has enough tokens to cover the balance and proceed to checkout for the items saved in the shopping cart.

Here is OpenZeppelin implementation

contract ERC827 is ERC20 {
function approve( address _spender, uint256 _value, bytes _data )
public returns (bool);
function transfer( address _to, uint256 _value, bytes _data )
public returns (bool);
function transferFrom( address _from, address _to, uint256
_value, bytes _data )
public returns (bool);
}

The standard definition of specified ERC-827 methods is:

approve(address _from, uint256 _value, byte _data) public returns (bool) : this method allows to approve the transfer of values and execute a call with the data sent during the approve function call. Potential risk is that allowance can be changed within this method and and the old one. One possible solution to mitigate the risk is to first reduce the spenders allowance to 0 and set the desire value afterwards. Here is example implementation:/** @dev Addition to ERC20 token methods. It allows to approve the transfer of value and execute a call with the sent data. Beware that changing an allowance with this method brings the risk that someone may use both the old and the new allowance by unfortunate transaction ordering. One possible solution to mitigate this race condition is to first reduce the spender's allowance to 0 and set the desired value afterwards:https://github.com/ethereum/EIPs/issues/20#issuecomment-263524729@param _spender The address that will spend the funds.
@param _value The amount of tokens to be spent.
@param _data ABI-encoded contract call to call `_to` address.
@return true if the call function was executed successfully
*/function approve(address _spender, uint256 _value, bytes _data)
public returns (bool) {
require(_spender != address(this));
require(super.approve(_spender, _value));
require(_spender.call(_data));
return true;
}
transfer(address _to, uint256 _value, bytes _data) public returns (bool) : this method transfers tokens from specified address and executes a call with the sent data on the same transaction.Method will return true if the called function is executed successfully. Example implementation:/**
@dev Addition to ERC20 token methods. Transfer tokens to a
specified address and execute a call with the sent data on the
same transaction
@param _to address The address which you want to transfer to
@param _value uint256 the amount of tokens to be transferred
@param _data ABI-encoded contract call to call `_to` address.
@return true if the call function was executed successfully
*/function transfer(address _to, uint256 _value, bytes _data) public
returns (bool) {
require(_to != address(this));
require(super.transfer(_to, _value));
require(_to.call(_data));
return true;
}
transferFrom(address _from, address _to, uint256 _value, bytes _data) public returns (bool) : this method like transfer() it also transfers tokens from one address to another and makes a contract call on the same transaction. The only difference is that this method can be used in coordination with approve() method and execute different logic while approving and transferring tokens. Example implementation:/**
@dev Addition to ERC20 token methods. Transfer tokens from one address to another and make a contract call on the same transaction
@param _from The address which you want to send tokens from
@param _to The address which you want to transfer to
@param _value The amount of tokens to be transferred
@param _data ABI-encoded contract call to call `_to` address.
@return true if the call function was executed successfully
*/function transferFrom(address _from, address _to, uint256 _value,
bytes _data) public returns (bool) {
require(_to != address(this));
super.transferFrom(_from, _to, _value);
require(_to.call(_data));
return true;
}

The Blockchain Hub is an inclusive education and innovation hub, with a strong network of diverse alumni from many industry verticals. Would you like to add your voice to ours, and have your articles featured in The Blockchain Hub? Just send us a note at content@theblockchainhub.com

Disclaimer: The views and opinions expressed in this article are those of the author. They do not purport to reflect the policies, views, opinions or positions of The Blockchain Hub, any other agency, entity, organization, employer or company.

Part 1 Part 2 Part 3

--

--

Dejan Jovanovic
TheBlockchainHub

Seasoned executive, business and technology leader, entrepreneur, blockchain and smart contract expert