Fatskills
Practice. Master. Repeat.
Study Guide: Blockchain and Web3 Development: Ethereum and Smart Contracts ERC Standards ERC20 ERC721 ERC1155
Source: https://www.fatskills.com/cryptocurrency-bitcoin-blockchain-and-more/chapter/blockchain-and-web3-development-blockchain-and-web3-development-ethereum-and-smart-contracts-erc-standards-erc20-erc721-erc1155

Blockchain and Web3 Development: Ethereum and Smart Contracts ERC Standards ERC20 ERC721 ERC1155

By Fatskills Exam Guides Team — the exam nerds behind 28,500+ quizzes and 2.1M practice questions across 500+ global exams.

⏱️ ~6 min read

What This Is

ERC (Ethereum Request for Comments) standards are a set of interface contracts that define how tokens behave on the Ethereum Virtual Machine. By agreeing on a common API, anyone can write wallets, exchanges, or marketplaces that work with any token that follows the standard—just like USB‑C works for every peripheral.
Real‑world example: A user clicks “Swap” on Uniswap, and the front‑end calls the ERC‑20 transferFrom function of the token they are selling; the same UI would work for DAI, USDC, or a brand‑new meme coin without any code changes.


Key Terms & Code Snippets

  • ERC‑20 – The baseline fungible‑token interface (totalSupply, balanceOf, transfer, approve, transferFrom).
    solidity 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); }

  • ERC‑721 – The non‑fungible token (NFT) standard; each token has a unique tokenId.
    solidity interface IERC721 {
    function ownerOf(uint256 tokenId) external view returns (address);
    function safeTransferFrom(address from, address to, uint256 tokenId) external;
    event Transfer(address indexed from, address indexed to, uint256 indexed tokenId); }

  • ERC‑1155 – A “multi‑token” standard that can hold both fungible and non‑fungible assets in one contract, saving gas with batch operations.
    solidity interface IERC1155 {
    function balanceOf(address account, uint256 id) external view returns (uint256);
    function safeBatchTransferFrom(address from, address to, uint256[] calldata ids, uint256[] calldata amounts, bytes calldata data) external;
    event TransferSingle(address indexed operator, address indexed from, address indexed to, uint256 id, uint256 value); }

  • approve / allowance pattern – Enables a third‑party (e.g., a DEX router) to move tokens on a user’s behalf.
    js // Ethers.js await token.approve(router.address, ethers.utils.parseUnits("1000", 18));

  • safeTransferFrom – ERC‑721/1155 function that checks the recipient implements the ERC‑721/1155 receiver interface, preventing tokens from being locked in contracts that can’t handle them.

  • Metadata URI – ERC‑721 and ERC‑1155 expose tokenURI(uint256) or uri(uint256) that points to off‑chain JSON (IPFS, Arweave) describing the asset.

  • supportsInterface(bytes4) – ERC‑165 method that lets contracts announce which ERC standards they implement (e.g., 0x80ac58cd for ERC‑721).

  • Batch Minting – ERC‑1155 lets you mint many token IDs in one transaction, cutting gas from ~50 k per NFT to ~5 k for a batch of 10.

  • transfer vs transferFromtransfer moves your own tokens; transferFrom moves tokens you’ve been approved for.

  • ERC20Burnable – Extension that adds a burn(uint256 amount) function, useful for deflationary tokenomics.

  • ERC721Enumerable – Optional ERC‑721 extension that lets you enumerate all tokens owned by an address (tokenOfOwnerByIndex).

  • ERC1155Holder – A helper contract that implements the receiver callbacks so your contract can safely hold ERC‑1155 tokens.


Step‑by‑Step / Process Flow

  1. Write the contract – Scaffold with OpenZeppelin in Remix or VS Code.
    bash
    npx hardhat init
    npm i @openzeppelin/contracts
  2. Compile & test – Use Hardhat’s built‑in compiler (solc 0.8.24) and write unit tests with Waffle/Chai.
    bash
    npx hardhat compile
    npx hardhat test
  3. Deploy to a testnet – Grab an Infura/Alchemy endpoint, fund a Goerli wallet, then run a deployment script.
    js
    const ERC20 = await ethers.getContractFactory("MyToken");
    const token = await ERC20.deploy("MyToken", "MTK", 18);
    await token.deployed();
    console.log("Deployed at:", token.address);
  4. Verify on Etherscannpx hardhat verify --network goerli <address> "MyToken" "MyToken" "MTK" 18.
  5. Interact from the front‑end – Connect MetaMask, instantiate the contract with Ethers.js, and call transfer, approve, or safeTransferFrom as needed.

Common Mistakes

  • Mistake: Forgetting to implement supportsInterface when adding ERC‑721/1155 extensions.
    Correction: Call ERC165.supportsInterface in your contract; otherwise marketplaces think the token is non‑compliant and refuse to list it.

  • Mistake: Using tx.origin for access control (e.g., require(tx.origin == owner)).
    Correction: Use msg.sender and OpenZeppelin’s Ownable; tx.origin can be spoofed through a malicious contract, opening a phishing vector.

  • Mistake: Approving an unlimited amount (type(uint256).max) for every token transfer.
    Correction: Approve only the exact amount needed for the operation; unlimited approvals are a common phishing target on DeFi platforms.

  • Mistake: Ignoring the ERC‑165 identifier when building a custom ERC‑1155 receiver.
    Correction: Return the correct magic value (0xf23a6e61) in onERC1155Received; otherwise the transfer will revert.

  • Mistake: Minting ERC‑721 tokens without emitting the Transfer event from the zero address.
    Correction: Use OpenZeppelin’s _safeMint which automatically emits the event; missing the event breaks indexers and wallets.


Blockchain Developer Interview / Practical Insights

  1. “Explain the difference between call and delegatecall.” – Interviewers want to see you understand that delegatecall runs the callee’s code in the caller’s storage context, a common pattern for upgradeable proxies but a source of re‑entrancy bugs.

  2. “When would you choose ERC‑1155 over ERC‑721?” – Expect to discuss batch minting, gas savings, and mixed fungible/non‑fungible collections (e.g., a game where each character (ERC‑721) holds consumable items (ERC‑1155)).

  3. “How does ERC‑777 improve on ERC‑20, and why isn’t it universally adopted?” – Talk about hooks (tokensReceived) and operator granularity, but also note the higher audit surface and limited tooling support.

  4. “What are the trade‑offs between Optimistic Rollups and ZK‑Rollups for token transfers?” – Mention latency vs. proof‑generation cost, and that ERC‑20 transfers on Optimism are cheap but require a fraud‑proof window, whereas ZK‑Rollups give instant finality but need heavy zk‑SNARK circuits.


Quick Check Questions

  1. Scenario: A contract calls token.transferFrom(msg.sender, address(this), amount) without first checking allowance.
    Answer: The transaction will revert if the allowance is insufficient.
    Why: transferFrom internally checks allowance and will fail, protecting the token holder from accidental overspending.

  2. Scenario: An NFT marketplace lists a token that does not implement ERC721Receiver.
    Answer: The marketplace’s safeTransferFrom will revert, preventing the NFT from being locked.
    Why: The ERC‑721 spec requires the recipient contract to return the magic value; otherwise the transfer is considered unsafe.

  3. Scenario: A DeFi protocol uses tx.origin == admin to restrict admin functions.
    Answer: This is insecure because a malicious contract can trick a user into calling the admin function, making tx.origin equal to the admin’s address.
    Why: tx.origin reflects the original external account, not the immediate caller, so it can be hijacked via phishing.


Last‑Minute Cram Sheet (10 one‑liners)

  1. ERC‑20 = 0x36372b07totalSupply, balanceOf, transfer, approve, transferFrom.
  2. ERC‑721 = 0x80ac58cd – Unique tokenId, ownerOf, safeTransferFrom.
  3. ERC‑1155 = 0xd9b67a26 – Multi‑token, batch safeBatchTransferFrom.
  4. ⚠️ Never rely on tx.origin for auth; always use msg.sender.
  5. Gas tip: Use unchecked {} for simple i++ loops in Solidity 0.8+ to save ~5 gas per iteration.
  6. Compiler: Most production contracts target solc >=0.8.20 for built‑in overflow checks and custom errors.
  7. Metadata: Store JSON off‑chain (IPFS CID) and return it via tokenURI(uint256).
  8. Upgradeability: ERC‑1967 proxy uses delegatecall; keep storage layout identical across upgrades.
  9. Allowance race: Use increaseAllowance/decreaseAllowance pattern to avoid the double‑spend race.
  10. ⚠️ ERC‑1155 receivers must return 0xf23a6e61 (single) or 0xbc197c81 (batch) or the transfer reverts.


ADVERTISEMENT