Most of what people do on Ethereum involves tokens — stablecoins, governance tokens, NFTs, in-game items. A token is nothing mysterious: it's just a smart contract that keeps a ledger of who owns what, using the patterns you've already learned. What makes tokens work across the whole ecosystem is standards: shared interfaces that every wallet, exchange, and app agrees to speak. This lesson explains what a token really is, the two standards you must know — ERC-20 and ERC-721 — and why you should almost never write one from scratch.
- Explain that a token is a contract tracking ownership, not a coin that 'moves'
- Describe the ERC-20 fungible-token interface and what each function does
- Explain how ERC-721 represents unique, non-fungible tokens (NFTs)
- Use audited standard implementations rather than writing your own
What a token actually is
A token does not 'live in your wallet' the way a file lives on your computer. A token is a smart contract that maintains a mapping of addresses to balances — a private little ledger of who owns how much. When you 'send 10 tokens to Bob,' nothing physically moves; the token contract simply subtracts 10 from your entry in its mapping and adds 10 to Bob's. Your wallet doesn't store the tokens; it stores your *keys*, and it reads your balance from the token contract. This is the mental shift: a token is a program that keeps score, and 'owning' a token means the token contract's ledger has an entry crediting your address.
Because a token is just a contract's internal ledger, adding a token to your wallet is only telling the wallet which contract address to read. The tokens were already 'yours' on-chain; importing the address just lets the wallet display the balance. Nothing is transferred by adding a token to your wallet.
Standards: why every token speaks the same language
If every token contract had different function names, no wallet or exchange could support them all. Standards solve this. A token standard is an agreed interface — a fixed set of function names and events every conforming contract must provide. Because a token follows the standard, any wallet, exchange, or app that speaks that standard can use it without custom code. This interoperability is the reason tokens exploded: build to the standard and the entire ecosystem supports your token automatically. The standards are called ERCs (Ethereum Request for Comments); ERC-20 for interchangeable tokens and ERC-721 for unique ones are the two that matter most.
ERC-20: fungible tokens
ERC-20 is the standard for fungible tokens — tokens that are all identical and interchangeable, like currency: any one unit is worth exactly the same as any other. Stablecoins, governance tokens, and most 'coins' built on Ethereum are ERC-20. The standard defines a small interface: totalSupply (how many exist), balanceOf(account) (an account's balance), transfer(to, amount) (send your own tokens), plus an approval mechanism — approve(spender, amount) and transferFrom(from, to, amount) — that lets you authorise another contract to spend a set amount on your behalf, which is how you interact with exchanges and DeFi. Two events, Transfer and Approval, announce these actions so wallets can track them.
// The heart of the ERC-20 interface every fungible token implements.
interface IERC20 {
function totalSupply() external view returns (uint256);
function balanceOf(address account) external view returns (uint256);
function transfer(address to, uint256 amount) external returns (bool);
function approve(address spender, uint256 amount) external returns (bool);
function transferFrom(address from, address to, uint256 amount) external returns (bool);
event Transfer(address indexed from, address indexed to, uint256 value);
event Approval(address indexed owner, address indexed spender, uint256 value);
}The approve / transferFrom pattern is worth understanding because it powers DeFi. You can't send tokens *into* another contract just by transferring; instead you approve that contract to withdraw up to some amount, and it then calls transferFrom to pull them when needed. This two-step 'allowance' is how a DEX or lending protocol moves your tokens with your permission but without holding your keys.
ERC-721: non-fungible tokens (NFTs)
ERC-721 is the standard for non-fungible tokens — each one is unique and not interchangeable. Where an ERC-20 tracks *how many* tokens each address holds, an ERC-721 tracks *which specific token* (by a unique tokenId) each address owns. That's the essence of an NFT: a ledger mapping each unique id to an owner. The interface centres on ownerOf(tokenId) (who owns a specific token) and balanceOf(owner) (how many an address owns), with transferFrom and safeTransferFrom to move a specific token. A tokenURI(tokenId) typically points to metadata — a name, an image link — usually stored off-chain (often on IPFS, a later lesson), because storing images on-chain would be enormously expensive.
A common misconception: the NFT is not the image. The NFT is the on-chain record of who owns tokenId 42; the image it points to almost always lives off-chain. This is why where the metadata is stored (and whether that storage is permanent) matters so much for an NFT's real durability.
Don't write it from scratch
You now understand what these standards require, which is exactly why you should reach for a battle-tested implementation rather than writing your own. OpenZeppelin publishes audited, widely used implementations of ERC-20, ERC-721, and more; you inherit from them and add only your specifics. Token contracts hold real value and a subtle bug is catastrophic and permanent, so re-implementing a standard yourself invites exactly the vulnerabilities audited libraries have already fixed. The professional pattern is to import the standard base, then extend it. Understanding the interface (this lesson) lets you use those libraries correctly and read what they do.
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.20;
import "@openzeppelin/contracts/token/ERC20/ERC20.sol";
contract MyToken is ERC20 {
constructor() ERC20("MyToken", "MTK") {
// mint an initial supply to the deployer (amount in wei-like units)
_mint(msg.sender, 1000000 * 10 ** decimals());
}
}That whole token — name, symbol, transfers, approvals, events — comes from inheriting the audited ERC20 base; you wrote only the constructor. This is exactly what the first blockchain project builds and deploys. With standards understood, the next stage moves to the tooling that lets you compile, test, and deploy contracts like this one for real.