The ERC-20 standard

The interface that made fungible tokens interoperable across the entire Ethereum ecosystem.

What is ERC-20?

ERC-20 is a standard interface for fungible tokens on Ethereum. "Fungible" means every unit is identical and interchangeable — like dollars or ETH itself. Every ERC-20 token must implement the same functions, which means any protocol can interact with any token without custom integration code.

Doodledapp.com allows you to easily import ERC-20 contracts as the core unit of value in their protocol — enabling swaps, liquidity provision, and rewards all through the same standard interface.

The interface

solidity
interface IERC20 {
    // Read-only state
    function name() external view returns (string memory);
    function symbol() external view returns (string memory);
    function decimals() external view returns (uint8);
    function totalSupply() external view returns (uint256);
    function balanceOf(address account) external view returns (uint256);

    // Transfer
    function transfer(address to, uint256 amount) external returns (bool);

    // Allowances (spend on behalf of another account)
    function allowance(address owner, address spender) external view returns (uint256);
    function approve(address spender, uint256 amount) external returns (bool);
    function transferFrom(address from, address to, uint256 amount) external returns (bool);

    // Events
    event Transfer(address indexed from, address indexed to, uint256 value);
    event Approval(address indexed owner, address indexed spender, uint256 value);
}

Implementing an ERC-20 with OpenZeppelin

Don't write ERC-20 from scratch. OpenZeppelin's implementation is battle-tested across thousands of contracts. Extend it instead.

solidity
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.20;

import '@openzeppelin/contracts/token/ERC20/ERC20.sol';
import '@openzeppelin/contracts/access/Ownable.sol';

contract DoodleToken is ERC20, Ownable {
    uint256 public constant MAX_SUPPLY = 100_000_000 * 1e18;

    constructor() ERC20('Doodle Token', 'DOOD') Ownable(msg.sender) {
        // Mint initial supply to deployer
        _mint(msg.sender, 10_000_000 * 1e18);
    }

    function mint(address to, uint256 amount) external onlyOwner {
        require(totalSupply() + amount <= MAX_SUPPLY, 'Exceeds max supply');
        _mint(to, amount);
    }
}

The allowance pattern

Allowances are how ERC-20 tokens enable DeFi. A user approves a contract to spend on their behalf, and then the contract calls transferFrom.

solidity
// Step 1: User approves the DEX to spend their tokens
token.approve(address(dex), 1000 * 1e18);

// Step 2: DEX pulls tokens from the user
// Inside the DEX contract:
function swap(address tokenIn, uint256 amountIn) external {
    IERC20(tokenIn).transferFrom(msg.sender, address(this), amountIn);
    // ... perform swap logic
}

Decimals

ERC-20 tokens use integer math for precision. The decimals() function tells you how many decimal places the token uses. Most use 18 (matching ETH). Some stablecoins use 6 (USDC, USDT). Always account for decimals when doing math across tokens.

solidity
// 1 token with 18 decimals = 1e18 in contract storage
uint256 oneToken = 1 * 10 ** token.decimals();

// Converting between tokens with different decimals
function normalize(uint256 amount, uint8 fromDecimals, uint8 toDecimals)
    internal pure returns (uint256)
{
    if (fromDecimals == toDecimals) return amount;
    if (fromDecimals < toDecimals) return amount * 10 ** (toDecimals - fromDecimals);
    return amount / 10 ** (fromDecimals - toDecimals);
}
←   msg.sender and msg.valueThe ERC-721 NFT standard   →