探索以太坊ERC20代币合约代码,从原理到实践

在区块链世界的“经济系统”中,代币无疑是连接价值、传递权益的核心载体,而以太坊作为智能合约平台的领军者,其ERC20标准(Ethereum Request for Comments 20)定义了代币合约的统一“语法规则”,使得不同代币能在以太坊生态中无缝交互,本文将深入解析ERC20代币合约的核心原理、代码结构,并手把手教你如何编写一个属于自己的ERC20代币合约。

ERC20标准:代币的“通用语言”

ERC20是以太坊社区提出的代币接口标准,于2015年11月通过,它并非一个具体的合约代码,而是一套规范,要求所有基于以太坊的代币合约必须实现特定的函数和事件,以确保兼容性,就像USB接口让不同设备能共用充电器一样,ERC20让钱包、交易所、DApp等工具能统一处理各类代币。

ERC20的核心接口规范

ERC20标准定义了6个必须实现的函数和2个必须触发的事件,构成了代币合约的“骨架”:

必须实现的函数

  1. name()
    返回代币的完整名称,如“USD Coin”“ChainLink Token”。
    示例返回值: "USD Coin"

  2. symbol()
    返回代币的简称,通常2-3个字符,如"USDC""LINK"。
    示例返回值: "USDC"

  3. decimals()
    返回代币的小数位数,用于精确计算(避免浮点数误差),以太坊主币ETH的decimals为18,多数代币也遵循此惯例。
    示例返回值: 18

  4. totalSupply()
    返回代币的总供应量,类型为uint256(无符号256位整数)。
    示例返回值: 1000000000000000000000000(即100万,假设decimals为18)

  5. balanceOf(address account)
    查询指定地址account的代币余额,返回uint256类型。
    参数: account - 要查询的地址
    示例返回值: 500000000000000000000(即500代币)

  6. transfer(address to, uint256 amount)
    向指定地址to转移amount数量的代币,调用者需有足够的余额。
    参数: to - 接收地址;amount - 转移数量(已乘以decimals)
    返回值: bool(成功返回true,失败抛出异常)

  7. transferFrom(address from, address to, uint256 amount)
    从地址from向地址to转移amount数量的代币,通常用于授权场景(如交易所批量提现),调用者需先被from地址授权足够的allowance
    参数: from - 转出地址;to - 接收地址;amount - 转移数量
    返回值: bool

  8. approve(address spender, uint256 amount)
    授权地址spender可调用transferFrom转移自己的代币,最大额度为amount
    参数: spender - 被授权地址;amount - 授权额度
    返回值: bool

  9. allowance(address owner, address spender)
    查询地址owner已授权给spender的代币额度。
    参数: owner - 授权方地址;spender - 被授权方地址
    返回值: uint256

必须触发的事件

  1. Transfer(address indexed from, address indexed to, uint256 value)
    在代币转移时触发(包括铸造和销毁)。

    • from:转出地址(铸造时为0x000...000,销毁时为接收地址);
    • to:接收地址(销毁时为0x000...000);
    • value:转移数量。
  2. Approval(address indexed owner, address indexed spender, uint256 value)
    在调用approve修改授权额度时触发。

    • owner:授权方;
    • spender:被授权方;
    • value:新的授权额度。

ERC20代币合约代码:从“骨架”到“血肉”

基于ERC20标准,我们可以编写一个完整的代币合约,以Solidity语言(以太坊智能合约开发语言)为例,以下是一个基础ERC20代币合约的完整代码,并附关键注释解析:

// SPDX-License-Identifier: MIT
// 指定许可证,MIT是开源合约常用许可证,允许自由使用和修改
pragma solidity ^0.8.20;
// 指定Solidity编译器版本,^0.8.20表示使用0.8.20及以上、0.9.0以下的版本
/**ERC20代币合约
 * @dev 实现ERC20标准接口,包含基本代币功能:铸造、转移、授权
 */
contract MyToken is ERC20 {
    address public owner; // 合约所有者地址,用于控制铸造权限
    /**
     * @dev 构造函数,在合约部署时执行
     * @param _name 代币名称
     * @param _symbol 代币简称
     */
    constructor(string memory _name, string memory _symbol) ERC20(_name, _symbol) {
        owner = msg.sender; // 将部署者地址设为所有者
        _mint(owner, 1000000 * 10**decimals()); // 初始铸造100万代币给所有者(自动乘以decimals)
    }
    /**
     * @dev 铸造新代币(仅所有者可调用)
     * @param _account 接收代币的地址
     * @param _amount 铸造数量(未乘以decimals)
     */
    function mint(address _account, uint256 _amount) public onlyOwner {
        _mint(_account, _amount * 10**decimals());
    }
    /**
     * @dev 销毁代币(调用者需有足够余额)
     * @param _amount 销毁数量(未乘以decimals)
     */
    function
随机配图
burn(uint256 _amount) public { _burn(msg.sender, _amount * 10**decimals()); } /** * @dev 销毁指定地址的代币(仅所有者可调用,可用于销毁错误发送的代币) * @param _account 要销毁代币的地址 * @param _amount 销毁数量(未乘以decimals) */ function burnFrom(address _account, uint256 _amount) public onlyOwner { _burnFrom(_account, _amount * 10**decimals()); } } // 继承OpenZeppelin的ERC20接口,避免重复造轮子(推荐做法) import "@openzeppelin/contracts/token/ERC20/ERC20.sol"; import "@openzeppelin/contracts/access/Ownable.sol";

代码关键点解析

继承OpenZeppelin的ERC20合约

实际开发中,不建议从零实现ERC20,而是使用OpenZeppelin(开源智能合约库)提供的标准化ERC20合约,它已通过多次安全审计,实现完整且安全,并包含常用功能(如权限控制、事件触发等),上述代码中,contract MyToken is ERC20表示MyToken合约继承自OpenZeppelin的ERC20合约。

构造函数(constructor

  • 在合约部署时执行,仅运行一次;
  • 通过ERC20(_name, _symbol)调用父合约(ERC20)的构造函数,设置代币名称和简称;
  • owner = msg.sender将合约部署者设为“所有者”,后续可通过onlyOwner修饰符限制敏感操作;
  • _mint()是ERC20合约内置的铸造函数,1000000 * 10**decimals()表示铸造100万代币(decimals()默认为18,所以实际铸造数量为1000000 * 10^18,即100万乘以精度单位)。

铸造(mint)与销毁(burn

  • mint:新增代币,需由所有者调用,避免无序增发导致通胀;
  • burn:销毁代币,调用者销毁自己的代币;
  • burnFrom:所有者销毁指定地址的代币(可用于回收错误发送的代币)。
    *注:铸造和销毁时,数量需手动乘以10**decimals(),因为用户输入的“100万”是实际代币数量,而合约内部存储的是最小单位(如“100万×10^18”)。*

4

本文由用户投稿上传,若侵权请提供版权资料并联系删除!