在区块链,尤其是以太坊生态系统中,代币(Token)扮演着至关重要的角色,无论是稳定币、治理代币还是实用型代币,它们绝大多数都遵循着一个统一的标准——ERC20,ERC20不仅是以太坊上代币的“身份证”,更是确保不同代币之间互操作性的基石,本文将深入探讨ERC20标准的核心概念,并详细解析其标准合约代码,帮助开发者理解其工作原理并能够进行实际开发。
什么是ERC20标准
ERC20(Ethereum Request for Comments 20)是一个以太坊网络上的技术标准,用于定义 fungible token(可替代代币,即每个代币完全相同,可以互换)的接口和功能,它由以太坊开发者Fabian Vogelsteller在2017年提出,并迅速成为以太坊上发行代币的最广泛采用的标准。
ERC20标准定义了一套必须实现的接口(函数)和必须遵循的事件规则,确保了所有ERC20代币都具有一致的行为,
- 转账:从一个地址发送代币到另一个地址。
- 授权:允许某个地址花费你代币账户中的代币。
- 查询:获取总供应量、某个地址的代币余额等。
这种一致性使得钱包、交易所、去中心化应用(DApp)等能够无缝地支持各种ERC20代币,而无需为每种代币进行单独的开发和适配。
ERC20标准的核心接口与事件
ERC20标准主要包含以下9个接口函数和2个事件,任何ERC20代币合约都必须实现这些函数和事件。
核心接口函数:

-
name() public view returns (string)- 功能:返回代币的全称,"USD Coin"。
- 示例:
"USD Coin"
-
symbol() public view returns (string)- 功能:返回代币的简称,通常是2-3个字符,"USDC"。
- 示例:
"USDC"
-
decimals() public view returns (uint8)- 功能:返回代币的小数位数,用于表示代币的最小单位,18位小数意味着1个代币可以分割为 10^18 个最小单位。
- 示例:
18
-
totalSupply() public view returns (uint256)- 功能:返回代币的总供应量。
- 示例:
1000000000000000000000000(表示100万,如果decimals是18)
-
balanceOf(address _owner) public view returns (uint256)- 功能:返回指定地址
_owner持有的代币数量。 - 参数:
_owner- 要查询余额的地址。 - 返回值:该地址的代币余额。
- 功能:返回指定地址
-
transfer(address _to, uint256 _value) public returns (bool success)- 功能:从调用者(msg.sender)的账户向
_to地址转移_value数量的代币。 - 参数:
_to- 接收代币的地址;_value- 要转移的代币数量。 - 返回值:操作是否成功。
- 要求:调用者必须有足够的余额,且转移操作必须触发
Transfer事件。
- 功能:从调用者(msg.sender)的账户向
-
transferFrom(address _from, address _to, uint256 _value) public returns (bool success)- 功能:从
_from地址向_to地址转移_value数量的代币,与transfer不同,此函数允许第三方(调用者)转移_from地址的代币,但前提是_from地址已通过approve()函数授权调用者转移的额度不少于_value。 - 参数:
_from- 源地址;_to- 目标地址;_value- 要转移的代币数量。 - 返回值:操作是否成功。
- 要求:调用者必须有来自
_from的足够授权额度,且_from必须有足够的余额,操作必须触发Transfer事件,并相应减少授权额度。
- 功能:从
-
approve(address _spender, uint256 _value) public returns (bool success)- 功能:允许
_spender地址最多花费调用者账户中的_value数量代币。 - 参数:
_spender- 被授权的地址;_value- 授权的代币数量。 - 返回值:操作是否成功。
- 要求:操作必须触发
Approval事件,如果对同一个_spender多次调用,新的_value将覆盖旧的授权值。
- 功能:允许
-
allowance(address _owner, address _spender) public view returns (uint256 remaining)- 功能:返回
_owner地址授权给_spender地址的、尚未使用的代币数量。 - 参数:
_owner- 代币所有者地址;_spender- 被授权的地址。 - 返回值:剩余的可授权额度。
- 功能:返回
核心事件:
-
Transfer(address indexed from, address indexed to, uint256 value)- 触发时机:当
transfer或transferFrom函数成功执行代币转移时触发。 - 参数:
from- 源地址(如果是代币铸造,则为0x0地址);to- 目标地址(如果是代币销毁,则为0x0地址);value- 转移的代币数量。
- 触发时机:当
-
Approval(address indexed owner, address indexed spender, uint256 value)- 触发时机:当
approve函数成功执行授权时触发。 - 参数:
owner- 代币所有者地址;spender- 被授权的地址;value- 授权的代币数量。
- 触发时机:当
ERC20标准合约代码示例(Solidity)
下面是一个简化但完整的ERC20标准合约代码示例,基于Solidity语言编写(通常使用Solidity ^0.8.0及以上版本,它内置了溢出检查等安全特性)。
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;
import "@openzeppelin/contracts/token/ERC20/ERC20.sol";
/**SimpleToken
* @dev 一个简单的ERC20代币合约示例
* 这个合约继承自OpenZeppelin的ERC20合约,它已经实现了所有ERC20标准的逻辑和事件。
* 继承是开发安全可靠ERC20代币的推荐做法。
*/
contract SimpleToken is ERC20 {
constructor(string memory name, string memory symbol, uint256 initialSupply) ERC20(name, symbol) {
// 在部署时,将初始供应量铸造给合约部署者(msg.sender)
_mint(msg.sender, initialSupply);
}
}
代码解析:
SPDX-License-Identifier: MIT:许可证标识符,表明该合约代码遵循MIT许可证。pragma solidity ^0.8.0;:指定Solidity编译器版本,^0.8.0表示使用0.8.0或更高版本(但不包括0.9.0)。import "@openzeppelin/contracts/token/ERC20/ERC20.sol";:导入OpenZeppelin库中的ERC20合约,OpenZeppelin是一个提供安全、审计过的智能合约标准库的组织,强烈建议在生产环境中使用其合约,以避免常见的安全漏洞。contract SimpleToken is ERC20:定义一个名为SimpleToken的合约,它继承自ERC20合约,这意味着SimpleToken自动获得了ERC20中所有已实现的函数(如name,symbol,transfer等)和事件(Transfer,Approval)。constructor(string memory name, string memory symbol, uint256 initialSupply) ERC20(name, symbol):constructor是合约的构造函数,仅在合约部署时执行一次。- 它接收三个参数:代币名称(
name)、代币符号(symbol)和初始供应量(initialSupply)。 ERC20(name, symbol)是调用父合约(ERC20)的构造函数,用于设置代币的名称和符号。
_mint(msg.sender, initialSupply);:_mint是OpenZeppelin ERC20合约中的一个内部函数,用于“铸造”新的代币,将其增加到指定地址的余额中,并相应增加总供应量。- 这里