Learn12 min read

ERC-20 Token Standard: Functions, Approvals & Token Creation

Master ERC-20 token standard in 2026. Learn 6 required functions (transfer, approve, balanceOf, allowance, totalSupply, transferFrom), approval vulnerabilities, ERC-4626 vault standard. Compare ERC-20 vs ERC-721 vs ERC-1155. OpenZeppelin implementation guide.

Updated: April 10, 2026Reading time: 12 min
D
DegenSensei·Content Lead
·
Apr 10, 2026
·
12 min read

What is ERC-20?

ERC-20 (Ethereum Request for Comments #20) is a standard interface for fungible tokens on Ethereum. Defines 6 required functions and 2 events that all tokens must implement. This standardization allows wallets, exchanges, and smart contracts to work with any ERC-20 token identically.

💡Why This Matters

Understanding this concept is a prerequisite for making informed decisions in DeFi. Most losses in crypto come from misunderstanding the fundamentals.

Why ERC-20 is Critical

Before ERC-20 (2014-2015): Each token had custom interface. Uniswap had to write custom code for USDC, USDT, DAI, UNI separately. Wallets couldn't display new tokens without updates. Exchanges took weeks to list new tokens.

After ERC-20 (2015-present): All tokens follow same interface. Uniswap works with any ERC-20 token instantly (no custom code needed). MetaMask displays any ERC-20 (just add contract address). Exchanges list tokens in 1 day. This is why ERC-20 is Ethereum's killer feature.

ERC-20 Popularity

Total ERC-20 Tokens: 500k+ deployed on Ethereum. Major tokens: USDC (40B tokens), USDT (40B), DAI (5B), UNI (1B), LINK (1B). Total TVL: $100B+ locked in ERC-20. Daily volume: $10B+ traded. ERC-20 is the most important token standard in crypto.

Key Insight: ERC-20 success enables Ethereum DeFi. Without standardized interface, DEXs/lending/bridges would be impossible. ERC-20 is foundational to entire Ethereum ecosystem.

The 6 Required ERC-20 Functions

Function 1: totalSupply()

function totalSupply() public view returns (uint256)

Returns total token supply (all tokens ever created, including burned). Example: USDC totalSupply() = 40,000,000,000 (40B tokens). Used by: Wallets (display market cap), analysis (token inflation rate).

Function 2: balanceOf(address account)

function balanceOf(address account) public view returns (uint256)

Returns balance of specific account. Example: balanceOf(0x123) = 1000 USDC (account holds 1k USDC). Used by: Wallets (display balance), DeFi (collateral checks), governance (voting power).

Function 3: transfer(address recipient, uint256 amount)

function transfer(address recipient, uint256 amount) public returns (bool)

Transfers tokens from caller to recipient. Emits Transfer event. Example: transfer(0x456, 100) sends 100 USDC from my wallet to 0x456. Requirements: Caller balance >= amount. Used by: Direct token transfers, simple payments.

Function 4: transferFrom(address sender, address recipient, uint256 amount)

function transferFrom(address sender, address recipient, uint256 amount) public returns (bool)

Transfers tokens from sender to recipient (caller is third party). Requires prior approval. Example: Uniswap calls transferFrom(user, Uniswap, 100 USDC). User must have called approve(Uniswap, 100) first. Used by: Smart contracts (swaps, loans, yield farming).

Function 5: approve(address spender, uint256 amount)

function approve(address spender, uint256 amount) public returns (bool)

Approves spender to transfer up to amount tokens on caller's behalf. Emits Approval event. Example: approve(Uniswap, 1000) allows Uniswap to spend 1000 USDC from my wallet. Requirements: Caller authorizes spender. Security: Used by DEXs, lending, yield farming (requires user approval step).

Function 6: allowance(address owner, address spender)

function allowance(address owner, address spender) public view returns (uint256)

Returns remaining spender allowance from owner. Example: allowance(user, Uniswap) = 500 (Uniswap can still spend 500 USDC). Used by: Smart contracts (check remaining approval before spending).

Common Workflow: (1) User calls approve(Uniswap, 1000) USDC. (2) Uniswap checks allowance(user, Uniswap) = 1000. (3) Uniswap calls transferFrom(user, Uniswap, 1000) USDC. (4) Uniswap completes swap. (5) allowance reduces to 0. This 3-step process (approve + check + transfer) is standard in DeFi.

Events & Decimal Precision

Required Events

Transfer Event: Emitted when tokens transferred. Logged on blockchain, indexed for searching. Example: Transfer(0x123, 0x456, 100) = "0x123 sent 100 tokens to 0x456."

Approval Event: Emitted when approval changed. Example: Approval(user, Spender, 1000) = "user approved spender for 1000 tokens."

These events allow blockchain explorers (Etherscan) to display transaction history. Wallets listen for Transfer events to update balances.

Decimal Precision

Problem: USDC has value $1. Smart contracts can't handle decimals (uint256 only). Solution: Use smallest unit (wei). USDC has 6 decimals. 1 USDC = 1,000,000 units. Example: Transfer 1000 USDC = Transfer 1000 * 10^6 = 1,000,000,000 units.

Decimals field: ERC-20 includes decimals (6 for USDC, 18 for most tokens). Wallets use this to display correctly. If user sends 1,000,000,000 units and decimals=6, wallet displays "1000 USDC" (divide by 10^6).

Common decimals: 18 (ETH, Uniswap), 8 (WBTC), 6 (USDC, USDT), 18 (most new tokens). Non-standard decimals (3, 7, 9) can cause issues with wallets/DEXs.

Token Standards Comparison

StandardChainFeaturesUse CasesNotable Tokens
ERC-20EthereumFungible, transferablePayments, DeFi, governanceUSDC, USDT, UNI, LINK
ERC-721EthereumNFTs, unique itemsArt, collectibles, gamingBored Ape, CryptoPunks
ERC-1155EthereumMulti-token, fungible + NFTGames, complex ecosystemsRaydium, Axie Infinity
ERC-4626EthereumVault tokens, yieldYield farming, vaultsYearn, Lido, Aave
BEP-20Binance Smart ChainSame as ERC-20 (BSC version)BSC ecosystemBUSD, CAKE, LINK

Choosing a Standard: Need to transfer tokens → ERC-20. Creating unique items → ERC-721. Games/multiple assets → ERC-1155. Yield bearing tokens → ERC-4626. New projects should use ERC-20 (most compatible) unless specific use case requires NFTs or multi-tokens.

Approval Vulnerabilities & Security

The Race Condition Attack

Scenario: User approves Uniswap for 1000 USDC. Later, user wants to reduce approval to 100 USDC (revoke most). User calls approve(Uniswap, 100). But before transaction mined, Uniswap's bot extracts remaining 1000 USDC (uses old allowance). Then approval reduced to 100. Result: Uniswap took 1000 instead of intended 100.

Root Cause

approve() overwrites previous allowance. No atomic check-and-update. If timing is bad, old allowance can be used before new value takes effect.

Fix 1: increaseAllowance / decreaseAllowance

function increaseAllowance(address spender, uint256 addedValue) public returns (bool)

Adds to existing allowance (doesn't overwrite). Safe way to increase approval. Always prefer to decrease then increase, never approve(0) directly.

Fix 2: ERC-2612 Permit

Signatures instead of approvals. No race condition. Example: User signs message "allow Uniswap to spend 100 USDC." User submits signature + transaction in one atomic step. No separate approve() needed. Benefits: (1) Single transaction (approve + swap in one tx). (2) No race condition. (3) Better UX. Adoption: Growing (Uniswap v4, OpenZeppelin supports).

Best Practices

  • Never approve infinite: avoid approve(spender, type(uint256).max) unless you trust spender completely.
  • Use increaseAllowance: When increasing approval, use increaseAllowance() instead of approve().
  • Check allowance before spending: Smart contracts should verify allowance >= amount before calling transferFrom().
  • Revoke immediately: When done with spender, call approve(spender, 0) to revoke.
  • Use Permit when possible: For new protocols, use ERC-2612 permit() signatures (gas efficient, safer).

Creating an ERC-20 Token

Step-by-Step Process

Step 1: Define Token Properties

  • Name: "USD Coin"
  • Symbol: "USDC"
  • Decimals: 6
  • Initial supply: 1,000,000 (or 0, mint later)

Step 2: Write Smart Contract

Use OpenZeppelin ERC20 library (battle-tested). Implement optional functions: mint(), burn(), pause(). Add access control (who can mint?). Example code (Solidity):

import "@openzeppelin/contracts/token/ERC20/ERC20.sol";

contract USDC is ERC20 {
  constructor(uint256 initialSupply) ERC20("USD Coin", "USDC") {
    _mint(msg.sender, initialSupply * 10 ** 6);
  }

  function mint(address to, uint256 amount) public {
    _mint(to, amount);
  }
}

Step 3: Test Smart Contract

  • Write unit tests (Hardhat, Truffle). Test mint/burn/transfer functions.
  • Test edge cases (overflow, underflow, zero address).
  • Verify compliance with ERC-20 spec.

Step 4: Security Audit

Submit to professional auditor (OpenZeppelin, Trail of Bits, Certora). Cost: $5k-$50k+. Time: 2-4 weeks. Critical for mainnet launches (even small bugs cost millions).

Step 5: Deploy to Ethereum

  • Choose testnet first (Goerli, Sepolia). Deploy, test in live environment.
  • Deploy to mainnet. Pay gas fees (~$500-$5k depending on gas price).
  • Verify source code on Etherscan (allows anyone to audit).

Step 6: Post-Launch Checklist

  • Monitor contract for bugs (price feed integration, balance checks).
  • Set up emergency pause mechanism (in case of exploit).
  • Community updates (roadmap, governance).

Timeline: Implementation (1-3 days) + Testing (3-7 days) + Audit (2-4 weeks) + Deployment (1 day) = ~1 month from start to mainnet. For USDC-like tokens (massive scale), add longer audit + governance phases.

ERC-4626 Vault Standard

What is ERC-4626?

ERC-4626 is standard interface for tokenized vaults. A vault is smart contract that accepts deposits, invests assets, and generates yield. Vault deposits tokens into strategy (e.g., Yearn lends to Aave), earns interest, distributes to shareholders.

Example: Yearn USDC Vault

  • User deposits 1000 USDC into Yearn vault.
  • Vault mints 950 yvUSDC (shares, accounting for fees).
  • Vault invests USDC in Aave (earn 5% APY).
  • After 1 year: vault earned $50 yield. Total assets: $1050.
  • User's 950 shares now worth: 950 * ($1050 / 1000 shares) = $997.50.
  • User earned $47.50 (net of fees).

ERC-4626 Functions

Key functions:

  • deposit(uint256 assets) → shares: User deposits assets, receives vault shares.
  • withdraw(uint256 shares) → assets: User burns shares, receives assets + accrued yield.
  • totalAssets(): Total vault assets (deposits + yield - losses).
  • convertToShares(uint256 assets) → shares: Asset-to-share conversion (accounting for yield/losses).
  • convertToAssets(uint256 shares) → assets: Share-to-asset conversion.

Advantages Over ERC-20

Standardization: Before ERC-4626, each vault had custom interface. Yearn Vault ≠ Aave Vault ≠ Compound Vault. No standard way to deposit/withdraw. ERC-4626 unifies vault interface.

Composability: ERC-4626 vault shares are ERC-20 tokens. Can stake yvUSDC in another protocol, swap on DEX, use as collateral. Enables "vault of vaults" (deposit into multiple strategies simultaneously).

Gas Efficiency: Single approval for deposits. No need to approve + deposit separately.

ERC-4626 Adoption

  • Yearn: Pioneered vault concept, adopting ERC-4626 for new vaults.
  • Aave: Considering ERC-4626 adoption for savings accounts.
  • Curve: Exploring for yield-bearing stablecoins.
  • Future: Expected to become standard for all yield protocols by 2027.

Key Insight: ERC-4626 is to vaults what ERC-20 is to tokens. Standardizes interface, enables composability, drives adoption. Any new DeFi protocol building yield products should implement ERC-4626.

FAQ

Can I create a token with more than 18 decimals?

Technically yes, but not recommended. Most DeFi assumes 18 decimals. Wallets may display incorrectly. Exchanges may reject. Use standard decimals: 6 (USDC, USDT), 8 (WBTC), 18 (most new tokens).

Is ERC-20 scalable enough for billions of transactions?

ERC-20 itself is scalable (Ethereum L1 bottleneck, not token standard). L2 solutions (Arbitrum, Optimism) process ERC-20 transfers at 4000+ TPS. For high-frequency trading, use L2 rollups.

What's the difference between burn and transfer to 0x0?

Burn: Token is removed from circulation permanently (totalSupply decreases). Transfer to 0x0: Token exists but is inaccessible (totalSupply stays same, but no one owns tokens). Burn is better for deflation mechanics.

Can I change token decimals after launch?

No. Token decimals are immutable after deploy. Changing would break all wallets/exchanges. If you want to "upgrade" token, launch new token and migrate holders (via airdrop or swap). Very painful process.

What's the gas cost to deploy an ERC-20?

~$500-$5,000 depending on current gas prices. Expect ~150k-200k gas units. Use OpenZeppelin minimal proxy patterns to reduce costs. Testnets (Goerli, Sepolia) are free.

Why can't users directly call transferFrom without approval?

Security. If approve wasn't required, anyone could steal your tokens. Approval ensures user explicitly authorizes spending. This 2-step process (approve + transferFrom) is intentional.

Is ERC-20 secure?

Yes, when implemented correctly. OpenZeppelin ERC-20 is battle-tested. Risks: (1) Custom implementations have bugs. (2) Approval vulnerabilities (race condition). (3) Missing access control (anyone can mint). Use OpenZeppelin library, run audits.

What happens if I approve a malicious contract?

Malicious contract can steal all your tokens (up to approved amount). Always read smart contract code before approving. Check Etherscan for audit badges. For new protocols, start with small approval amount, increase if safe.

Can I make tokens deflationary (burn on transfer)?

Yes. Implement burn in transfer function (burn small % of transfer). Example: transfer(to, 100) burns 1, transfers 99. Reduces total supply over time. Used by: SafeMoon, Shiba Inu (v1). Side effect: reduces value of holders' tokens (not recommended).

What's the difference between approve and increaseAllowance?

approve(spender, 100): Sets allowance to exactly 100 (overwrites previous). increaseAllowance(spender, 100): Adds 100 to existing allowance. If allowance was 50, it becomes 150. Use increaseAllowance to avoid race conditions.

Educational disclaimer: This guide is for informational purposes only and does not constitute financial advice. Crypto involves significant risk — do your own research before making any decisions. Learn more about our team.

Educational disclaimer: This guide is for informational purposes only and does not constitute financial advice. Crypto involves significant risk — do your own research before making any decisions. Learn more about our team.