乐闻世界logo
搜索文章和话题

什么是ERC-20代币标准?请详细说明ERC-20的接口规范和实现方法

2月21日 16:06

ERC-20是以太坊上最广泛使用的代币标准,定义了同质化代币的接口规范。以下是ERC-20标准的详细解析:

ERC-20标准概述

ERC-20代表"Ethereum Request for Comments 20",由Fabian Vogelsteller于2015年提出。它定义了一套标准接口,使不同代币能够在以太坊生态系统中互操作。

必须实现的方法

1. totalSupply()

返回代币的总供应量。

solidity
function totalSupply() external view returns (uint256) { return _totalSupply; }

2. balanceOf(address account)

返回指定账户的代币余额。

solidity
function balanceOf(address account) external view returns (uint256) { return _balances[account]; }

3. transfer(address recipient, uint256 amount)

从调用者账户转移代币到接收者账户。

solidity
function transfer(address recipient, uint256 amount) external returns (bool) { _transfer(_msgSender(), recipient, amount); return true; }

4. allowance(address owner, address spender)

返回授权给spender的代币数量。

solidity
function allowance(address owner, address spender) external view returns (uint256) { return _allowances[owner][spender]; }

5. approve(address spender, uint256 amount)

授权spender使用调用者的代币。

solidity
function approve(address spender, uint256 amount) external returns (bool) { _approve(_msgSender(), spender, amount); return true; }

6. transferFrom(address sender, address recipient, uint256 amount)

使用授权额度从sender账户转移代币到recipient账户。

solidity
function transferFrom(address sender, address recipient, uint256 amount) external returns (bool) { _transfer(sender, recipient, amount); uint256 currentAllowance = _allowances[sender][_msgSender()]; require(currentAllowance >= amount, "ERC20: transfer amount exceeds allowance"); unchecked { _approve(sender, _msgSender(), currentAllowance - amount); } return true; }

可选实现的方法

1. name()

返回代币名称。

solidity
function name() external view returns (string memory) { return _name; }

2. symbol()

返回代币符号。

solidity
function symbol() external view returns (string memory) { return _symbol; }

3. decimals()

返回代币的小数位数,通常为18。

solidity
function decimals() external view returns (uint8) { return _decimals; }

事件(Events)

1. Transfer

代币转移时触发。

solidity
event Transfer(address indexed from, address indexed to, uint256 value);

2. Approval

授权时触发。

solidity
event Approval(address indexed owner, address indexed spender, uint256 value);

完整的ERC-20实现示例

solidity
// SPDX-License-Identifier: MIT pragma solidity ^0.8.0; contract MyToken { string private _name; string private _symbol; uint8 private _decimals; uint256 private _totalSupply; mapping(address => uint256) private _balances; mapping(address => mapping(address => uint256)) private _allowances; constructor(string memory name_, string memory symbol_, uint256 initialSupply) { _name = name_; _symbol = symbol_; _decimals = 18; _totalSupply = initialSupply; _balances[msg.sender] = initialSupply; emit Transfer(address(0), msg.sender, initialSupply); } function name() external view returns (string memory) { return _name; } function symbol() external view returns (string memory) { return _symbol; } function decimals() external view returns (uint8) { return _decimals; } function totalSupply() external view returns (uint256) { return _totalSupply; } function balanceOf(address account) external view returns (uint256) { return _balances[account]; } function transfer(address recipient, uint256 amount) external returns (bool) { _transfer(msg.sender, recipient, amount); return true; } function allowance(address owner, address spender) external view returns (uint256) { return _allowances[owner][spender]; } function approve(address spender, uint256 amount) external returns (bool) { _approve(msg.sender, spender, amount); return true; } function transferFrom(address sender, address recipient, uint256 amount) external returns (bool) { _transfer(sender, recipient, amount); uint256 currentAllowance = _allowances[sender][msg.sender]; require(currentAllowance >= amount, "ERC20: transfer amount exceeds allowance"); unchecked { _approve(sender, msg.sender, currentAllowance - amount); } return true; } function _transfer(address sender, address recipient, uint256 amount) internal { require(sender != address(0), "ERC20: transfer from the zero address"); require(recipient != address(0), "ERC20: transfer to the zero address"); uint256 senderBalance = _balances[sender]; require(senderBalance >= amount, "ERC20: transfer amount exceeds balance"); unchecked { _balances[sender] = senderBalance - amount; _balances[recipient] += amount; } emit Transfer(sender, recipient, amount); } function _approve(address owner, address spender, uint256 amount) internal { 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); } }

使用OpenZeppelin库

OpenZeppelin提供了经过审计的ERC-20实现,推荐在生产环境中使用。

solidity
// SPDX-License-Identifier: MIT pragma solidity ^0.8.0; import "@openzeppelin/contracts/token/ERC20/ERC20.sol"; import "@openzeppelin/contracts/access/Ownable.sol"; contract MyToken is ERC20, Ownable { constructor(uint256 initialSupply) ERC20("My Token", "MTK") { _mint(msg.sender, initialSupply); } function mint(address to, uint256 amount) public onlyOwner { _mint(to, amount); } }

ERC-20的应用场景

1. 去中心化金融(DeFi)

  • 流动性提供
  • 借贷协议
  • 衍生品交易

2. 治理代币

  • DAO投票
  • 协议治理
  • 社区激励

3. 稳定币

  • USDT、USDC、DAI
  • 法币抵押
  • 算法稳定

4. 实用代币

  • 平台访问权限
  • 服务支付
  • 奖励机制

ERC-20的局限性

1. 授权机制问题

  • 需要两次交易(approve + transferFrom)
  • 可能导致授权额度泄露

2. 缺乏批量操作

  • 每次转移都需要单独交易
  • Gas成本较高

3. 无法处理代币回调

  • 不支持接收代币时的通知
  • 可能导致代币丢失

其他ERC代币标准

ERC-721

非同质化代币(NFT)标准,每个代币都是唯一的。

ERC-1155

多代币标准,支持同质化和非同质化代币。

ERC-777

改进的ERC-20标准,支持代币回调和批量操作。

ERC-4626

金库代币标准,用于DeFi收益聚合器。

最佳实践

  1. 使用OpenZeppelin库:避免重复造轮子,使用经过审计的代码
  2. 添加访问控制:实现适当的权限管理
  3. 事件日志:记录所有重要操作
  4. 安全审计:在部署前进行专业审计
  5. 测试覆盖:确保充分的测试覆盖率

ERC-20标准是以太坊生态系统的基础,理解其工作原理对于开发区块链应用至关重要。

标签:以太坊