Skip to content

ERC20 标准实现

1. 系统概述

ERC20 标准实现是一个基于 Solidity 实现的标准代币合约,完全符合 ERC20 标准接口规范。该实现包含了代币的基本功能和扩展功能,并添加了必要的安全机制。

1.1 主要特点

  • 标准兼容:完全符合 ERC20 标准
  • 基础功能:转账、授权、查询等基本操作
  • 扩展功能:增加/减少授权等扩展操作
  • 事件追踪:完整的事件日志记录
  • 安全检查:完善的安全性验证
  • 精确计算:支持小数位配置

2. 合约实现

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 标准代币实现
 */
contract ERC20 is Context {
    using SafeMath for uint256;

    // 状态变量
    string private _name;                   // 代币名称
    string private _symbol;                 // 代币符号
    uint8 private _decimals;               // 小数位数
    uint256 private _totalSupply;          // 总供应量

    mapping(address => uint256) private _balances;                      // 账户余额
    mapping(address => mapping(address => uint256)) private _allowances; // 授权额度

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

    /**
     * @dev 构造函数
     */
    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_;
        
        // 初始化总供应量
        _mint(_msgSender(), totalSupply_);
    }

    /**
     * @dev 获取代币名称
     */
    function name() public view returns (string memory) {
        return _name;
    }

    /**
     * @dev 获取代币符号
     */
    function symbol() public view returns (string memory) {
        return _symbol;
    }

    /**
     * @dev 获取小数位数
     */
    function decimals() public view returns (uint8) {
        return _decimals;
    }

    /**
     * @dev 获取总供应量
     */
    function totalSupply() public view returns (uint256) {
        return _totalSupply;
    }

    /**
     * @dev 获取账户余额
     */
    function balanceOf(address account) public view returns (uint256) {
        return _balances[account];
    }

    /**
     * @dev 获取授权额度
     */
    function allowance(address owner, address spender) public view returns (uint256) {
        return _allowances[owner][spender];
    }

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

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

    /**
     * @dev 授权转账
     */
    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 增加授权额度
     */
    function increaseAllowance(address spender, uint256 addedValue) public returns (bool) {
        address owner = _msgSender();
        _approve(owner, spender, _allowances[owner][spender].add(addedValue));
        return true;
    }

    /**
     * @dev 减少授权额度
     */
    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 内部转账函数
     */
    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 内部铸币函数
     */
    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 内部销毁函数
     */
    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 内部授权函数
     */
    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 内部扣减授权额度函数
     */
    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. 功能说明

3.1 基础功能

  • 代币信息查询:名称、符号、小数位、总供应量
  • 账户余额查询:查询指定账户的代币余额
  • 授权额度查询:查询授权给指定账户的代币额度

3.2 交易功能

  • 转账:直接转账给其他账户
  • 授权:授权其他账户使用代币
  • 授权转账:使用授权额度转账

3.3 扩展功能

  • 增加授权:增加对指定账户的授权额度
  • 减少授权:减少对指定账户的授权额度
  • 铸币和销毁:内部函数支持代币的铸造和销毁

4. 安全机制

4.1 地址验证

  • 零地址检查:禁止与零地址进行交互
  • 地址有效性验证:确保地址格式正确

4.2 数值检查

  • 余额充足性检查:确保转账和销毁操作有足够余额
  • 授权额度验证:确保授权转账在授权额度内
  • 数值溢出保护:使用 SafeMath 防止数值溢出

4.3 状态管理

  • 原子性操作:确保状态更新的原子性
  • 事件记录:记录所有重要操作的事件
  • 授权管理:安全的授权额度管理

5. 使用示例

5.1 部署代币

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);
await token.deployed();

5.2 转账代币

javascript
const to = "0x1234...";
const amount = ethers.utils.parseEther("100");
await token.transfer(to, amount);

5.3 授权和授权转账

javascript
// 授权
const spender = "0x5678...";
const amount = ethers.utils.parseEther("1000");
await token.approve(spender, amount);

// 授权转账
const from = "0x1234...";
const to = "0x9012...";
await token.transferFrom(from, to, amount);

6. 总结

该 ERC20 标准实现提供了一个完整的代币合约,包括:

  • 完全符合 ERC20 标准的接口实现
  • 安全的代币转账和授权机制
  • 完善的数值检查和地址验证
  • 灵活的授权管理功能
  • 详细的事件记录系统

通过严格遵循 ERC20 标准并添加必要的安全检查,该实现为开发者提供了一个可靠、安全的代币合约基础。

常见问题解答(FAQ)

Q: 什么是 ERC20 标准?

A: ERC20 是以太坊上最广泛使用的代币标准之一,它定义了一组接口规范,使得代币可以在以太坊网络上统一地进行转账、授权等操作。

Q: 为什么需要授权(Approve)机制?

A: 授权机制允许代币持有者授权其他地址(如智能合约)代表自己使用一定数量的代币,这对于 DEX、借贷等 DeFi 应用是必需的。

Q: 代币的小数位(Decimals)是什么意思?

A: 小数位定义了代币的最小可分割单位。例如,decimals = 18 意味着 1 个代币可以分割成 10^18 个最小单位。

Q: 如何防止代币合约被攻击?

A: 主要通过以下方式:

  • 使用 SafeMath 防止数值溢出
  • 严格的地址检查
  • 完善的权限控制
  • 全面的安全测试

Q: 如何处理误转入合约的代币?

A: 建议实现额外的恢复机制,但标准的 ERC20 实现并不包含这个功能。如果代币被误转到合约地址,且合约没有相应的处理函数,这些代币可能会永久丢失。

Released under the MIT License by Vogeb.