Skip to main content

What Is ERC-20? The Ethereum Token Standard Explained

ERC-20 is Ethereum's standard interface for fungible tokens: six required functions, two events, three optional fields, and the known pitfalls.

· By ZIPMEX · 11 min read

ERC-20 is a standard interface for fungible tokens on Ethereum. It is not a token. It is a set of functions and events that a smart contract must implement so that wallets, decentralised exchanges and other applications can work with the token without custom code. Fabian Vogelsteller and Vitalik Buterin wrote it as EIP-20, created on 19 November 2015. Its status is Final.

What "ERC-20" means

EIP stands for Ethereum Improvement Proposal. ERC is the category of EIPs for "application-level standards and conventions, including contract standards such as token standards", and ERC-20 is the example EIP-1 itself gives. The number 20 is the proposal's number.

The EIP sets out its motivation in one line: a standard interface "allows any tokens on Ethereum to be re-used by other applications", from wallets to decentralised exchanges.

ERC-20 tokens and ether are different things

Ether (ETH) is Ethereum's native currency. It is not an ERC-20 token. An ERC-20 token is a balance ledger kept inside a smart contract deployed on Ethereum. In practice this means:

  • Each token has its own contract, and that contract records who holds how much.
  • Moving an ERC-20 token is a call to its contract, so it costs gas. Gas fees "have to be paid in Ethereum's native currency, ether (ETH)". A wallet holding only an ERC-20 token and no ETH cannot send that token on its own.
  • ERC-20 tokens are fungible: every unit of a given token is identical in type and value to every other unit.

The interface

Required functions

FunctionWhat it does
totalSupply()Returns the total token supply
balanceOf(address _owner)Returns the balance of an address
transfer(address _to, uint256 _value)Sends tokens from the caller to _to
transferFrom(address _from, address _to, uint256 _value)Moves tokens from _from to _to on behalf of an approved spender
approve(address _spender, uint256 _value)Lets _spender withdraw up to _value from the caller's account, multiple times
allowance(address _owner, address _spender)Returns how much _spender may still withdraw from _owner

Required events

  • Transfer(address indexed _from, address indexed _to, uint256 _value)
  • Approval(address indexed _owner, address indexed _spender, uint256 _value)

Optional fields

  • name(): for example, a full token name
  • symbol(): a short ticker
  • decimals(): the number of decimals the token uses. The EIP's example: 8 means you divide the raw amount by 100,000,000 to get the amount a user sees.

The standard says other contracts "MUST NOT expect these values to be present." The figure "maximum 18 decimals" that often goes with this list does not come from the standard. decimals() returns a uint8, and 18 is a common convention, not a limit.

How do your ERC-20 tokens move?

Answer three questions to see which ERC-20 path you are on and which rule from the standard applies to it.

  1. Does the wallet that holds the token also hold some ETH?

  2. Where are the tokens going?

  3. Have you already set an allowance for that contract with approve?

You need ETH for gas first

Moving an ERC-20 token is a call to its contract, and gas is paid in ether (ETH). A wallet with only the token and no ETH cannot send the token on its own.

Direct transfer

A direct transfer calls transfer, and the tokens leave your address. The standard says it SHOULD throw if your balance is too low. Check that the address is not a contract that cannot handle tokens: ERC-20 cannot notify a receiving contract, so tokens sent to one can be permanently lost.

Approve first, then the contract pulls

Do not send the tokens with a plain transfer. Call approve(spender, amount) to set an allowance, and the contract then calls transferFrom to move up to that amount. Your first interaction takes two transactions. If the token supports ERC-2612 permit, a signed message can set the allowance instead of a separate approve transaction.

The contract can call transferFrom

The spender contract can move up to your remaining allowance with transferFrom. The allowance function shows how much it may still withdraw.

Set the allowance to 0 before the new value

Calling approve again overwrites the allowance; it does not add to it. Because of an attack vector on approve and transferFrom, the EIP advises user interfaces to set the allowance to 0 before setting a new value for the same spender.

This follows the rules of the EIP-20 text only: it does not check any particular token contract, whether a contract handles tokens safely, gas costs, audits or legal status.

How the two transfer paths work

Direct transfer. You call transfer and the tokens leave your address. The EIP says this SHOULD throw if your balance is too low.

Approve, then transferFrom. This is how smart contracts take tokens from you, for example when you deposit into a protocol:

  1. You call approve(spender, amount), which sets an allowance.
  2. The spender contract calls transferFrom(you, recipient, amount) and moves up to that allowance.

transferFrom SHOULD throw unless the _from account "has deliberately authorized the sender". Calling approve again overwrites the existing allowance. It does not add to it.

Rules developers get wrong

  • Handle false. Callers "MUST handle false from returns (bool success)" and "MUST NOT assume that false is never returned".
  • Zero-value transfers are real transfers. They must be treated as normal and must fire the Transfer event.
  • Minting. A contract that creates new tokens SHOULD emit Transfer with _from set to 0x0.
  • Changing an allowance. The EIP warns about an attack vector on approve/transferFrom. It advises user interfaces to set the allowance to 0 before setting a new value for the same spender. The contract itself should not enforce this.

Known problems and later standards

Tokens sent to contracts can be lost

ERC-20 has no way to notify a receiving contract. Tokens sent with transfer to a contract that cannot handle them "can be permanently lost". ethereum.org puts the losses at no less than $83,656,418 as of 20 June 2024. The mitigations it lists:

  • Make transfer revert when someone tries to send tokens to the token contract itself.
  • Deposit into contracts with approve plus transferFrom, not a plain transfer.
  • Build contracts so that tokens sent by mistake can be withdrawn.
  • Consider alternative standards such as ERC-223 or ERC-1363.

Two transactions and the ETH requirement

Because approve depends on msg.sender, a user's first interaction with a contract takes two transactions, and the user must hold ETH for gas. ERC-2612 (Final, created 13 April 2020, by Martin Lundfall) adds a permit function. It sets an allowance from a signed message, so no separate approve transaction is needed:

``solidity function permit(address owner, address spender, uint value, uint deadline, uint8 v, bytes32 r, bytes32 s) external ``

ethereum.org lists ERC-777, ERC-4626 (tokenized vaults) and ERC-7540 (asynchronous tokenized vaults) alongside ERC-20.

Implementations

The EIP points to two reference implementations, from OpenZeppelin and ConsenSys. It notes that they make different trade-offs, for example gas savings against improved security. Most new tokens build on an audited library rather than writing the interface from scratch.

Limitations: this guide covers the standard's text and ethereum.org's documentation. It does not cover token audits, individual token contracts or legal status.

Updated on Oct 25, 2026