了解 ERC-20 代币智能合约
以太坊上最重要的智能合约标准之一被称为 ERC-20,它已经成为以太坊区块链上所有用于实现同质化代币的智能合约的技术标准。
ERC-20 定义了一组所有以太坊同质化代币都应遵守的通用规则。因此,该代币标准使各类开发者能够准确预测新代币在更广泛的以太坊系统中的运作方式。这简化并减轻了开发者的任务,因为他们可以继续推进工作,并且知道只要代币遵循这些规则,就不必在每次发布新代币时重做每一个新项目。
下面以接口的形式展示了 ERC-20 必须实现的函数。如果你不确定什么是接口:请查看我们关于 Solidity 中的面向对象编程 (OOP) (opens in a new tab) 的文章。
pragma solidity ^0.6.0;
interface IERC20 {
function totalSupply() external view returns (uint256);
function balanceOf(address account) external view returns (uint256);
function allowance(address owner, address spender) external view returns (uint256);
function transfer(address recipient, uint256 amount) external returns (bool);
function approve(address spender, uint256 amount) external returns (bool);
function transferFrom(address sender, address recipient, uint256 amount) external returns (bool);
event Transfer(address indexed from, address indexed to, uint256 value);
event Approval(address indexed owner, address indexed spender, uint256 value);
}
下面逐行解释每个函数的用途。在此之后,我们将展示一个简单的 ERC-20 代币实现。
获取器
function totalSupply() external view returns (uint256);
返回存在的代币数量。此函数是一个获取器,不会修改合约的状态。请记住,Solidity 中没有浮点数。因此,大多数代币采用 18 位小数,并会返回总供应量和其他结果,例如 1 个代币表示为 1000000000000000000。并非每个代币都有 18 位小数,这是在处理代币时需要特别注意的地方。
function balanceOf(address account) external view returns (uint256);
返回某个地址 (account) 拥有的代币数量。此函数是一个获取器,不会修改合约的状态。
function allowance(address owner, address spender) external view returns (uint256);
ERC-20 标准允许一个地址向另一个地址提供授权额度,使其能够从中提取代币。此获取器返回 spender 被允许代表 owner 消费的剩余代币数量。此函数是一个获取器,不会修改合约的状态,并且默认应返回 0。
函数
function transfer(address recipient, uint256 amount) external returns (bool);
将 amount 数量的代币从函数调用者地址 (msg.sender) 转账到接收者地址。此函数会触发稍后定义的 Transfer 事件。如果转账成功,则返回 true。
function approve(address spender, uint256 amount) external returns (bool);
设置允许 spender 从函数调用者 (msg.sender) 余额中转账的 allowance 数量。此函数会触发 Approval 事件。该函数返回授权额度是否成功设置。
function transferFrom(address sender, address recipient, uint256 amount) external returns (bool);
使用授权额度机制将 amount 数量的代币从 sender 转账到 recipient。然后从调用者的授权额度中扣除该数量。此函数会触发 Transfer 事件。
事件
event Transfer(address indexed from, address indexed to, uint256 value);
当代币数量 (value) 从 from 地址发送到 to 地址时,会触发此事件。
在铸造新代币的情况下,转账通常是 from 0x00..0000 地址,而在销毁代币的情况下,转账是 to 0x00..0000。
event Approval(address indexed owner, address indexed spender, uint256 value);
当代币数量 (value) 被 owner 批准供 spender 使用时,会触发此事件。
ERC-20 代币的基本实现
以下是构建你的 ERC-20 代币的最简单代码基础:
pragma solidity ^0.8.0;
interface IERC20 {
function totalSupply() external view returns (uint256);
function balanceOf(address account) external view returns (uint256);
function allowance(address owner, address spender) external view returns (uint256);
function transfer(address recipient, uint256 amount) external returns (bool);
function approve(address spender, uint256 amount) external returns (bool);
function transferFrom(address sender, address recipient, uint256 amount) external returns (bool);
event Transfer(address indexed from, address indexed to, uint256 value);
event Approval(address indexed owner, address indexed spender, uint256 value);
}
contract ERC20Basic is IERC20 {
string public constant name = "ERC20Basic";
string public constant symbol = "ERC";
uint8 public constant decimals = 18;
mapping(address => uint256) balances;
mapping(address => mapping (address => uint256)) allowed;
uint256 totalSupply_ = 10 ether;
constructor() {
balances[msg.sender] = totalSupply_;
}
function totalSupply() public override view returns (uint256) {
return totalSupply_;
}
function balanceOf(address tokenOwner) public override view returns (uint256) {
return balances[tokenOwner];
}
function transfer(address receiver, uint256 numTokens) public override returns (bool) {
require(numTokens <= balances[msg.sender]);
balances[msg.sender] = balances[msg.sender]-numTokens;
balances[receiver] = balances[receiver]+numTokens;
emit Transfer(msg.sender, receiver, numTokens);
return true;
}
function approve(address delegate, uint256 numTokens) public override returns (bool) {
allowed[msg.sender][delegate] = numTokens;
emit Approval(msg.sender, delegate, numTokens);
return true;
}
function allowance(address owner, address delegate) public override view returns (uint) {
return allowed[owner][delegate];
}
function transferFrom(address owner, address buyer, uint256 numTokens) public override returns (bool) {
require(numTokens <= balances[owner]);
require(numTokens <= allowed[owner][msg.sender]);
balances[owner] = balances[owner]-numTokens;
allowed[owner][msg.sender] = allowed[owner][msg.sender]-numTokens;
balances[buyer] = balances[buyer]+numTokens;
emit Transfer(owner, buyer, numTokens);
return true;
}
}
ERC-20 代币标准的另一个优秀实现是 欧本齐柏林 ERC-20 实现 (opens in a new tab)。