The ERC-20 Standard

When we talk about a token in the context of Ethereum, we usually mean an ERC-20 token. ERC-20 is currently the most used token standard. There are over 100,000 ERC-20-based tokens on the Ethereum network currently, and almost all Ethereum wallets and wallet interfaces support them. Thanks to standards like ERC-20, wallet (interface) developers only need to implement support once, and all the ERC-20-based tokens will work.

To understand what ERC-20 is, it’s important to know what an ERC is first. ERC stands for Ethereum Request for Comment. An ERC starts off as an EIP, Ethereum Improvement Proposal. When an EIP is approved, it will become a new ERC. The ERC-20 standard can be found here.

Below you’ll find the ERC-20 interface, a set of functions and events that an ERC-20 smart contract must implement.

The ERC-20 interface written in Solidity.

Wallet interfaces, exchanges, or other dApps (decentralized applications) using tokens can use these functions to provide support for all ERC-20-compliant tokens.

ERC-20 has some optional functions as well, such as to get the name, symbol, and number of decimals the token uses.

function name() public view returns (string) function symbol() public view returns (string) function decimals() public view returns (uint8)

MyCrypto and other applications like MetaMask and Etherscan use these functions to get the metadata for a token.

As explained earlier in this article, ERC-20 transfers are relatively simple. The transfer function is called and the tokens are moved to the receiving address. ERC-20 has two ways to transfer tokens:

You can use the transfer function to send tokens from your address to another address.

function to send tokens from your address to another address. You can use the transferFrom function to send tokens from a different address to another address when you’re authorized to do so. We’ll get back to that in a bit.

Decimals

In one of the earlier versions of MyCrypto, when you added a token, you had to manually specify the number of decimals the token uses. When you look up a token contract on Etherscan, you’ll see the number of decimals as well:

Number of decimals used by the DAI token contract.

This number is important because the EVM does not know how to deal with decimal numbers: only full numbers are used. This includes regular transactions and token transactions. Instead, a full number with all the decimal numbers behind it is used. For example, if you have 3.14159 DAI and we assume DAI has 5 decimals (to make it easier), the balance stored in the smart contract is 314159. Multiply this with 10⁻⁵ and you get your actual balance again.

This doesn’t just apply to tokens; Ether is stored in the same way, with the smallest unit being 1 Wei. Since Ether has a maximum of 18 decimals (1 Wei = 0.000000000000000001 ETH), most tokens use this number as well.

Approving Transactions and Allowance

You may have noticed that when you interact with dApps like Compound or most decentralized exchanges, you have to send a transaction to approve spending a specific token first. When you do this, you allow the contract of the dApp to send tokens on your behalf. Without it, it would be significantly harder or even impossible to interact with ERC-20 tokens for dApps.

This is done by calling the approve method of the token. You specify the address of the spender (the dApp contract) and the value the spender can spend. Most dApps specify the maximum 256-bit number value (2²⁵⁶ -1), basically allowing them to spend an infinite number of tokens on your behalf.

Most (or all) token implementations use a simple mapping to store the allowance.

mapping (address => mapping (address => uint256)) private _allowed;

You can see this as a list of lists. A similar JSON notation would be:

{

"allowed": {

"0x4bbeEB066eD09B7AEd07bF39EEe0460DFa261520": {

"0x3FDA67f7583380E67ef93072294a7fAc882FD7E7": 100000

}

}

}

Here 0x4bbe…1520 allows 0x3FDA…D7E7 (Compound) to spend 100.000 of this specific token. Compound (or any other allowed smart contract) can then use ERC-20’s transferFrom method to transfer tokens from 0x4bbe…1520.

ETH as an ERC-20 Token

ERC-20 was developed after the creation of Ethereum (obviously), so ETH itself is not ERC-20 compliant. This can make it harder for smart contracts to interact with ETH and tokens at the same time, for example, when trading a token for Ether on a decentralized exchange (DEX). That’s why we have Wrapper Ether (wETH), developed by Radar Relay. WETH is an ERC-20 compliant token, with a value of exactly 1 ETH per token. You can always deposit or withdraw your ETH for wETH and vice-versa. It always maintains a one-to-one peg with ETH.

To wrap your ETH, you can simply send it to the contract address, and to withdraw it, you can call the withdraw method of the contract. Usually, dApps have a way to wrap and unwrap your ETH built in to the interface to make it easier.

The Problems of ERC-20

While ERC-20 has helped the adoption of Ethereum and Ethereum-based tokens massively, it does have some problems.

First off, it’s possible to send tokens to a contract that doesn’t support tokens. Since sending tokens involves sending a call to the token contract, most (non-token) contracts are not made to send or receive tokens, meaning that the tokens simply get stuck in the contract forever. Currently, there’s about 28,000 DAI in the DAI token contract that cannot be moved.

Secondly, contracts are not notified of a token transaction when using transfer . Since the balance is updated in a contract internally, there’s no way for a third-party contract to tell if a transaction happened. There is a workaround for this, but it involves using approve to authorize the third-party contract and using transferFrom in that contract. This means you need to send two transactions for a single token transfer.

Lastly, there is an issue where an authorized address could potentially transfer tokens from the owner’s address twice, as described here. This is caused by a possible race condition, where the authorized address could transfer tokens just before the owner changes the allowance.

A race condition could allow address B to transfer more tokens.

Address A authorized address B to spend 100 tokens. Address B sends 50 tokens from address A to another address. Address A decides to lower the maximum limit for Address B to 25. Address B notices this, and tries to send a transaction to spend 50 tokens (1). If this transaction is completed before the transaction of Address A, Address B can spend another 25 tokens (2) for a total of 125.

You could say that this isn’t really a problem with ERC-20 since most dApps ask you to authorize spending an infinite number of tokens anyway, but it’s still something to be aware of.

There are some other token standards like ERC-223 and ERC-777 that try to solve these problems. We’ll go into detail about these standards later in this article.