ERC-20 is the Ethereum standard for fungible tokens: every unit is identical and interchangeable, like shares of the same class or dollars in an account. It defines six functions and two events that let any wallet, exchange or smart contract hold and move a token without custom integration. Almost every stablecoin, governance token and tokenized money-market fund is ERC-20 or ERC-20-compatible — including ERC-3643 security tokens, which extend it with identity checks.
Key takeaways
- ERC-20 standardises balances, transfers and allowances for fungible tokens; it was finalised in 2015 and is the most widely supported token interface.
- It is ideal for money-like and unit-like assets: stablecoins, settlement coins, fund units, commodity-backed tokens.
- Plain ERC-20 has no compliance controls — anyone can send to anyone — so regulated securities use extensions such as ERC-3643, ERC-1404 or ERC-7943.
- Known pitfalls include the approve/transferFrom race condition, tokens lost to contracts, and inconsistent return values in older tokens.
How ERC-20 works
An ERC-20 contract is essentially a ledger mapping addresses to balances, plus a second ledger of allowances that let one address spend on behalf of another. The interface is small:
| Function / event | Purpose |
|---|---|
totalSupply() |
Total tokens in existence |
balanceOf(owner) |
Balance of an address |
transfer(to, amount) |
Move tokens from the caller |
approve(spender, amount) |
Allow a spender to move up to amount |
allowance(owner, spender) |
Remaining approved amount |
transferFrom(from, to, amount) |
Spender moves tokens within the allowance |
Transfer event |
Emitted on every movement, including mint (from zero address) and burn (to zero address) |
Approval event |
Emitted when an allowance changes |
Optional metadata — name, symbol and decimals — tells interfaces how to display balances. A token with 6 decimals (common for dollar stablecoins) stores 1.00 as 1000000.
Because the interface is identical across tokens, a DEX, a lending protocol or a custody platform can support any new ERC-20 with zero code changes. That network effect is the standard’s real value.
Where ERC-20 fits in real-world asset tokenization
Stablecoins and settlement coins
Fiat-backed stablecoins are ERC-20 tokens with issuer-controlled minting, burning and (usually) blacklisting. Corporate treasuries use the same pattern for settlement coins that net intercompany payments — something we have built for group entities. See tokenized deposits vs stablecoins.
Tokenized funds and treasuries
Most tokenized money-market and Treasury funds issue fund units as ERC-20 (or ERC-20-compatible) tokens with transfer restrictions added. When yield accrues inside a vault, ERC-4626 layers deposit and redemption logic on top of ERC-20 shares. Read more in tokenized treasuries and money-market funds.
Commodity-backed tokens
Gold, silver and other commodities held in vaults are naturally fungible: one token per gram or ounce, with proof of reserve attestations reconciling supply against inventory.
Purpose-bound and investment coins
Stablecoins can be restricted so they can only be spent with approved counterparties or for approved purposes — a pattern we used for an investment coin issued for a specific programme.
Why plain ERC-20 is not enough for securities
ERC-20’s openness is a feature for DeFi and a problem for securities law. A securities issuer must be able to:
- Prevent transfers to investors who have not passed KYC or are not eligible in their jurisdiction.
- Enforce lock-ups, holding limits and maximum-holder counts.
- Freeze tokens on regulatory or court instruction, and recover tokens from lost wallets.
- Know the full holder register at all times.
None of that exists in ERC-20. The common solutions are:
- ERC-3643 — ERC-20-compatible tokens with an identity registry and modular compliance. The default for regulated issuance on EVM chains.
- ERC-1404 — a lightweight interface adding
detectTransferRestrictionand human-readable restriction messages. - ERC-7943 — a minimal, finalised interface for
canTransfer, freezing and forced transfers that can sit on ERC-20, 721 or 1155. - Custom transfer hooks — overriding the internal update function to call your own compliance service.
Common ERC-20 pitfalls (and fixes)
The approval race condition
Changing an allowance from N to M lets a watching spender use N and then M. Fix: set to zero first, use increaseAllowance-style helpers, or use signed permits via ERC-2612.
Tokens sent to contracts
transfer does not check whether the recipient can handle tokens, so tokens sent to the token contract itself or to a non-aware contract are often lost forever. ERC-777 and ERC-1155 introduced receiver hooks to address this, at the cost of re-entrancy risk.
Non-standard return values
Some early tokens do not return a boolean. Integrators should use safe-transfer wrappers (e.g. OpenZeppelin SafeERC20).
Decimals and rounding
Distributions of interest or rent across thousands of holders introduce rounding dust. Decide how dust is handled — carried forward, swept to a reserve or paid to the last holder — and document it.
Designing an ERC-20 for an RWA programme
When we design an ERC-20-based RWA token we specify, at minimum:
- Roles — minter, burner, pauser, compliance agent, upgrade admin — each held by multisig or governed contracts, never a single hot key.
- Supply policy — how mint and burn tie to off-chain subscriptions, redemptions and reserve reports.
- Transfer policy — open, whitelisted or identity-gated (ERC-3643).
- Distribution mechanism — rebasing balances, accruing share price, or periodic claims.
- Upgradeability — proxy pattern and governance (see ERC-1967 proxies).
- Events for reconciliation — every off-chain ledger entry should map to an on-chain event.
ERC-20 compared with other standards
| Need | Better fit |
|---|---|
| One fungible asset, broad DeFi access | ERC-20 |
| Regulated security with eligibility rules | ERC-3643 (ERC-20 compatible) |
| Many asset classes in one contract | ERC-1155 |
| Unique items or titles | ERC-721 |
| Yield-bearing vault shares | ERC-4626 |
Our ERC-20 vs ERC-721 vs ERC-1155 comparison goes deeper.
A minimal, production-minded ERC-20 for an RWA programme
The snippet below shows the shape of an issuer-controlled ERC-20 with role separation, pausing and a compliance hook. It is illustrative only — production code needs a specification, full tests and an independent audit.
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.24;
import {ERC20} from "@openzeppelin/contracts/token/ERC20/ERC20.sol";
import {AccessControl} from "@openzeppelin/contracts/access/AccessControl.sol";
import {Pausable} from "@openzeppelin/contracts/utils/Pausable.sol";
interface ICompliance { function canTransfer(address from, address to, uint256 amount) external view returns (bool); }
contract FundUnit is ERC20, AccessControl, Pausable {
bytes32 public constant MINTER_ROLE = keccak256("MINTER_ROLE");
bytes32 public constant PAUSER_ROLE = keccak256("PAUSER_ROLE");
ICompliance public compliance;
constructor(address admin, ICompliance c) ERC20("Example Fund Unit", "EFU") {
_grantRole(DEFAULT_ADMIN_ROLE, admin); // a multisig, never an EOA
compliance = c;
}
function mint(address to, uint256 amt) external onlyRole(MINTER_ROLE) { _mint(to, amt); }
function burn(address from, uint256 amt) external onlyRole(MINTER_ROLE) { _burn(from, amt); }
function pause() external onlyRole(PAUSER_ROLE) { _pause(); }
function unpause() external onlyRole(PAUSER_ROLE) { _unpause(); }
// Every balance change — mint, burn, transfer — passes through _update.
function _update(address from, address to, uint256 amt) internal override whenNotPaused {
if (from != address(0) && to != address(0)) {
require(compliance.canTransfer(from, to, amt), "transfer not compliant");
}
super._update(from, to, amt);
}
}
Three design choices matter here. First, compliance is checked in the internal _update function so no transfer path can bypass it. Second, minting and pausing are separate roles, each held by a multisig or a governed contract. Third, compliance logic lives in a separate contract, so rules can evolve without migrating balances. If you need a complete, standardised version of this pattern, use ERC-3643.
Distribution models for income-bearing ERC-20 tokens
How do holders receive yield, interest or rent? There are three common approaches, each with different accounting, tax and integration effects:
| Model | How it works | Pros | Cons |
|---|---|---|---|
| Accruing price | Token count fixed; NAV per token rises | Simple for DeFi; no balance changes | Needs a NAV feed; investors see value, not cash |
| Rebasing | Balances increase automatically | Price stays at a reference value (e.g. $1) | Breaks many integrations; harder accounting |
| Periodic distribution | Stablecoins or new tokens paid on a record date | Mirrors traditional dividends and coupons | Requires snapshots and claim or push mechanics |
For real-world assets we usually recommend periodic distributions using a snapshot and pull-based claims: the contract records each holder’s entitlement at the record date and holders (or a relayer on their behalf) claim it. Pull-based claims avoid unbounded loops over thousands of holders and make failed payments easy to retry.
Mint and burn: tying supply to the real world
An RWA token is only credible if supply always matches the asset. Good practice:
- Mint only against confirmed subscriptions — after cash has settled and the investor has been verified.
- Burn on redemption in the same workflow that pays the investor out.
- Reconcile daily between the token’s total supply and the transfer agent’s or administrator’s register.
- Publish reserves or NAV through an oracle for collateral-backed tokens — see proof of reserve.
- Cap minting per transaction or per day to limit damage if a minter key is compromised.
Integration checklist for wallets, custodians and venues
Before launch, confirm that your ERC-20 works with every party in the chain:
- Custodians can whitelist the contract and show balances correctly (decimals, symbol).
- Venues understand any transfer restrictions and surface failure reasons to users.
- Explorers show verified source code and, for proxies, the implementation.
- Accounting systems ingest
Transferevents and map them to ledger entries. - Your investor portal handles failed transfers gracefully, explaining eligibility issues in plain language.
Frequently asked questions
Only with additional controls. Use an ERC-20-compatible security standard such as ERC-3643, or add restriction logic and an identity layer.
Not by default. Many issuers add pause, blacklist or partial-freeze functions controlled by an agent role; ERC-3643 and ERC-7943 standardise these.
ERC-3643 is ERC-20-compatible but checks every transfer against an identity registry and compliance rules. Wallets see a normal token; transfers to ineligible wallets simply fail.
Yes. Every EVM-compatible chain — Polygon, Arbitrum, Base, Avalanche, BNB Chain, Hedera’s EVM — supports ERC-20.
Match the unit you are representing. Fund units often use 6 or 18 decimals; dollar-pegged tokens commonly use 6. Avoid decimals that create rounding problems in distributions.
Usually yes, behind a proxy with multisig and timelock control, so bugs or regulatory changes can be handled. See ERC-1967 proxies.
Yes, through a distribution contract that snapshots balances and lets holders claim stablecoins, or by adjusting NAV per token.
This article is for general information only and is not legal, tax or investment advice. Token standards evolve — always confirm the current status of an ERC at eips.ethereum.org and take advice from qualified counsel in each jurisdiction before issuing tokens.


