Skip to content

ERC20 Standard Implementation

1. System Overview

The ERC20 standard implementation is a standard token contract implemented in Solidity that fully complies with the ERC20 standard interface specification. This implementation includes basic token functionality and extended features, along with necessary security mechanisms.

1.1 Main Features

  • Standard compliance: Fully compliant with ERC20 standard
  • Basic functions: Transfer, approval, query, and other basic operations
  • Extended features: Increase/decrease allowance and other extended operations
  • Event tracking: Complete event logging
  • Security checks: Comprehensive security validation
  • Precise calculation: Support for decimal configuration

2. Contract Implementation

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

import "@openzeppelin/contracts/utils/Context.sol";
import "@openzeppelin/contracts/utils/math/SafeMath.sol";

/**
 * @title ERC20 Token
 * @dev ERC20 standard token implementation
 */
contract ERC20 is Context {
    using SafeMath for uint256;

    // State variables
    string private _name;                   // Token name
    string private _symbol;                 // Token symbol
    uint8 private _decimals;               // Decimal places
    uint256 private _totalSupply;          // Total supply

    mapping(address => uint256) private _balances;                      // Account balances
    mapping(address => mapping(address => uint256)) private _allowances; // Allowance amounts

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

    /**
     * @dev Constructor
     */
    constructor(
        string memory name_,
        string memory symbol_,
        uint8 decimals_,
        uint256 totalSupply_
    ) {
        require(bytes(name_).length > 0, "ERC20: name is empty");
        require(bytes(symbol_).length > 0, "ERC20: symbol is empty");
        
        _name = name_;
        _symbol = symbol_;
        _decimals = decimals_;
        
        // Initialize total supply
        _mint(_msgSender(), totalSupply_);
    }

    /**
     * @dev Get token name
     */
    function name() public view returns (string memory) {
        return _name;
    }

    /**
     * @dev Get token symbol
     */
    function symbol() public view returns (string memory) {
        return _symbol;
    }

    /**
     * @dev Get decimal places
     */
    function decimals() public view returns (uint8) {
        return _decimals;
    }

    /**
     * @dev Get total supply
     */
    function totalSupply() public view returns (uint256) {
        return _totalSupply;
    }

    /**
     * @dev Get account balance
     */
    function balanceOf(address account) public view returns (uint256) {
        return _balances[account];
    }

    /**
     * @dev Get allowance amount
     */
    function allowance(address owner, address spender) public view returns (uint256) {
        return _allowances[owner][spender];
    }

    /**
     * @dev Transfer tokens
     */
    function transfer(address to, uint256 amount) public returns (bool) {
        address owner = _msgSender();
        _transfer(owner, to, amount);
        return true;
    }

    /**
     * @dev Approve allowance
     */
    function approve(address spender, uint256 amount) public returns (bool) {
        address owner = _msgSender();
        _approve(owner, spender, amount);
        return true;
    }

    /**
     * @dev Transfer tokens with allowance
     */
    function transferFrom(
        address from,
        address to,
        uint256 amount
    ) public returns (bool) {
        address spender = _msgSender();
        _spendAllowance(from, spender, amount);
        _transfer(from, to, amount);
        return true;
    }

    /**
     * @dev Increase allowance amount
     */
    function increaseAllowance(address spender, uint256 addedValue) public returns (bool) {
        address owner = _msgSender();
        _approve(owner, spender, _allowances[owner][spender].add(addedValue));
        return true;
    }

    /**
     * @dev Decrease allowance amount
     */
    function decreaseAllowance(address spender, uint256 subtractedValue) public returns (bool) {
        address owner = _msgSender();
        uint256 currentAllowance = _allowances[owner][spender];
        require(currentAllowance >= subtractedValue, "ERC20: decreased allowance below zero");
        unchecked {
            _approve(owner, spender, currentAllowance - subtractedValue);
        }
        return true;
    }

    /**
     * @dev Internal transfer function
     */
    function _transfer(
        address from,
        address to,
        uint256 amount
    ) internal virtual {
        require(from != address(0), "ERC20: transfer from the zero address");
        require(to != address(0), "ERC20: transfer to the zero address");

        uint256 fromBalance = _balances[from];
        require(fromBalance >= amount, "ERC20: transfer amount exceeds balance");
        unchecked {
            _balances[from] = fromBalance - amount;
            _balances[to] += amount;
        }

        emit Transfer(from, to, amount);
    }

    /**
     * @dev Internal mint function
     */
    function _mint(address account, uint256 amount) internal virtual {
        require(account != address(0), "ERC20: mint to the zero address");

        _totalSupply = _totalSupply.add(amount);
        unchecked {
            _balances[account] += amount;
        }
        emit Transfer(address(0), account, amount);
    }

    /**
     * @dev Internal burn function
     */
    function _burn(address account, uint256 amount) internal virtual {
        require(account != address(0), "ERC20: burn from the zero address");

        uint256 accountBalance = _balances[account];
        require(accountBalance >= amount, "ERC20: burn amount exceeds balance");
        unchecked {
            _balances[account] = accountBalance - amount;
            _totalSupply -= amount;
        }

        emit Transfer(account, address(0), amount);
    }

    /**
     * @dev Internal approve function
     */
    function _approve(
        address owner,
        address spender,
        uint256 amount
    ) internal virtual {
        require(owner != address(0), "ERC20: approve from the zero address");
        require(spender != address(0), "ERC20: approve to the zero address");

        _allowances[owner][spender] = amount;
        emit Approval(owner, spender, amount);
    }

    /**
     * @dev Internal spend allowance function
     */
    function _spendAllowance(
        address owner,
        address spender,
        uint256 amount
    ) internal virtual {
        uint256 currentAllowance = allowance(owner, spender);
        if (currentAllowance != type(uint256).max) {
            require(currentAllowance >= amount, "ERC20: insufficient allowance");
            unchecked {
                _approve(owner, spender, currentAllowance - amount);
            }
        }
    }
}

3. Function Description

3.1 Basic Functions

  • Token information query: name, symbol, decimals, total supply
  • Account balance query: query token balance of specified account
  • Allowance query: query token allowance granted to specified account

3.2 Core Functions

  • Transfer: token transfer between accounts
  • Approve: authorize spending allowance
  • TransferFrom: transfer tokens with allowance

3.3 Extended Functions

  • Increase allowance: increase spending allowance
  • Decrease allowance: decrease spending allowance
  • Mint: create new tokens (internal)
  • Burn: destroy tokens (internal)

4. Security Mechanisms

4.1 Access Control

  • Zero address check
  • Balance verification
  • Allowance validation
  • Overflow protection

4.2 State Management

  • Balance tracking
  • Allowance tracking
  • Total supply management
  • Event logging

4.3 Error Handling

  • Requirement checks
  • Error messages
  • State rollback
  • Event notifications

5. Usage Examples

5.1 Deploy Token

javascript
const name = "My Token";
const symbol = "MTK";
const decimals = 18;
const totalSupply = ethers.utils.parseEther("1000000");
const token = await ERC20.deploy(name, symbol, decimals, totalSupply);

5.2 Transfer Tokens

javascript
const amount = ethers.utils.parseEther("100");
await token.transfer(recipient.address, amount);

5.3 Approve and TransferFrom

javascript
// Approve
const amount = ethers.utils.parseEther("50");
await token.approve(spender.address, amount);

// TransferFrom
await token.connect(spender).transferFrom(owner.address, recipient.address, amount);

6. Summary

The ERC20 standard implementation provides:

  • Complete standard compliance
  • Secure token operations
  • Extended functionality
  • Comprehensive error handling
  • Event tracking

Frequently Asked Questions (FAQ)

1. Basic Concepts

Q: What is ERC20? A: ERC20 is a token standard that defines:

  • Basic token functions
  • Event specifications
  • Interface requirements
  • State management
  • Security requirements

Q: Why use ERC20? A: Benefits include:

  • Wide compatibility
  • Standard interface
  • Proven security
  • Easy integration
  • Community support

Q: How to handle decimals? A: Decimal handling:

javascript
// Convert to token units
const amount = ethers.utils.parseUnits("100", decimals);

// Convert from token units
const humanReadable = ethers.utils.formatUnits(amount, decimals);

Q: How to manage allowances? A: Allowance management:

  • Use approve for initial setting
  • Use increaseAllowance for increases
  • Use decreaseAllowance for decreases
  • Check allowance before transfers

Q: What are common security risks? A: Main risks include:

  • Overflow/underflow
  • Unauthorized transfers
  • Allowance attacks
  • Reentrancy issues
  • Front-running attacks

Q: How to ensure transfer safety? A: Safety measures:

  • Balance checks
  • Address validation
  • SafeMath usage
  • Event logging
  • Access control

4. Best Practices

Q: What are deployment recommendations? A: Key considerations:

  • Initial supply planning
  • Decimal places selection
  • Permission settings
  • Testing verification
  • Audit completion

Q: How to optimize gas usage? A: Optimization strategies:

  • Batch operations
  • State caching
  • Gas limit settings
  • Code optimization
  • Event optimization

Released under the MIT License by Vogeb.