ERC-20 is the standard interface for fungible tokens on Ethereum. Proposed by Fabian Vogelsteller in 2015 (EIP-20), it defines six functions and two events that every compliant token must implement. Because wallets, DEXs, lending protocols, and aggregators all speak ERC-20, any token that implements the interface is instantly composable with the entire ecosystem.
The interface#
|
|
The two-step approve + transferFrom pattern is the standard way for a smart contract to spend tokens on behalf of a user. The user first approves a spending allowance, then the contract calls transferFrom to pull the tokens.
Non-standard tokens and gotchas#
The ERC-20 spec says transfer and transferFrom must return bool, but several widely-used tokens deviate:
USDT (no return value)#
Tether’s transfer and approve functions return nothing. A Solidity contract that checks the return value with require(token.transfer(...)) will revert when interacting with USDT, because the EVM interprets the missing return data as a failed bool decode.
Fee-on-transfer tokens#
Some tokens deduct a fee on every transfer. If your contract assumes that the amount received equals the amount sent, accounting will silently break. The safe pattern is to measure the balance before and after the transfer:
|
|
Rebasing tokens#
Tokens like stETH change every holder’s balance automatically. Contracts that cache a balance and assume it stays constant will miscalculate. Most DeFi protocols use the wrapped, non-rebasing variant (wstETH) instead.
Approval race condition#
If a user calls approve to change an existing non-zero allowance, a malicious spender can front-run and spend both the old and new allowances. The standard mitigation is to set the allowance to zero first, then set the new value — or use increaseAllowance / decreaseAllowance (not part of the ERC-20 spec but widely available in OpenZeppelin’s implementation).
SafeERC20#
OpenZeppelin’s SafeERC20 library wraps all ERC-20 calls to handle non-standard tokens. It:
- Uses low-level
calland checks the return data length, accepting bothtrueand empty return values. - Provides
safeTransfer,safeTransferFrom,safeApprove,safeIncreaseAllowance, andsafeDecreaseAllowance.
Always use SafeERC20 when writing contracts that interact with arbitrary tokens:
|
|
Permit (EIP-2612)#
EIP-2612 extends ERC-20 with a permit function that allows approvals via off-chain signatures instead of a separate on-chain approve transaction. The user signs a typed message; the contract calls permit to set the allowance and transferFrom in a single transaction. This saves gas and improves UX, especially on L2s.
Related standards#
| Standard | Purpose |
|---|---|
| ERC-721 | Non-fungible tokens (NFTs) — each token has a unique ID. |
| ERC-1155 | Multi-token standard — supports both fungible and non-fungible tokens in one contract. |
| ERC-777 | Backwards-compatible extension with hooks for send/receive. Never gained wide adoption due to reentrancy concerns. |
| ERC-4626 | Tokenised vault standard — extends ERC-20 with deposit/withdraw/redeem for yield-bearing vaults. |
External links#
- EIP-20 specification — the canonical standard
- OpenZeppelin ERC20 implementation — battle-tested reference implementation
- OpenZeppelin SafeERC20 — library documentation
- EIP-2612: Permit — gasless approval extension