文章目录
- ERC-20协议是什么意思?
- 取值函数
- totalSupply
- balanceOf
- allowance
- 操作函数
- transfer
- approve
- transferFrom
- 事件
- Transfer
- Approval
- ERC-20 通证的基本实现
ERC-20协议是什么意思?
ERC代表“Etuereum Request for Comment”,以太坊社区为了创建一个以太坊平台的标准,开发人员提交了一个以太坊改进方案(EIP),改进方案中包括协议规范和合约标准。最终确定的EIP为以太坊开发者提供了一套可实施的标准。这使得智能合约可以遵循这些通用的接口标准来构建。可以在这里检索到所有EIP提案。
而ERC-20是以太坊上最重要的智能合约标准之一。它已经成为基于以太坊公链上用于发行可替换通证,所使用智能合约的技术标准。ERC-20 定义了所有可替换的以太坊通证都应该遵守的通用规则列表。 这简化了开发者的任务,开发者知道只要通证遵循标准中的规则,每次发布新的通证时就不需要重新实现每个新项目。
知识点:什么是可替换的以太坊通证,还有不可替换的以太坊通证吗?
可替换的以太坊通证是表示通证与通证之间是完全一样的,可以被替换的,通常遵循ERC-20标准。比如A钱包中的一个ERC-20通证和B钱包中的一个相同合约地址的ERC-20通证,在区块链上看来完全一致没有什么不同,可以被相互替换。
不可替换的以太坊通证又叫非同质化通证(Non-Fungible Token)缩写为NFT,就算AB两个钱包中存在合约地址相同的两个通证,它们也存在着不一致的属性值,它们是不一样的。所以在区块链上看来是不可被相互替换的。这样的通证通常遵循ERC-721标准。
这里有段 ERC-20 接口代码,它定义了遵循 ERC-20 标准通证所必须实现的函数:
pragma solidity ^0.8.0;interface IERC20 {event Transfer(address indexed from, address indexed to, uint256 value);event Approval(address indexed owner,address indexed spender,uint256 value);function totalSupply() external view returns (uint256);function balanceOf(address account) external view returns (uint256);function allowance(address owner, address spender)externalviewreturns (uint256);function transfer(address to, uint256 amount) external returns (bool);function approve(address spender, uint256 amount) external returns (bool);function transferFrom(address from,address to,uint256 amount) external returns (bool);}
下面说明一下这些函数的用途
取值函数
totalSupply
这个函数返回存在的通证数量,展示了目前该通证的流通总量,可以被所有函数调取。该函数是一个取值函数,不会修改合约的状态。重点:Solidity 中没有浮点数。 因此,大多数通证都会采用 18 位小数,并且会返回总供应量和其他结果,如下所示:1 个通证 = 100000000000000000。 这需要在处理通证数量时格外注意,不过并不是每个通证都有 18 位小数。
function totalSupply() external view returns (uint256);
balanceOf
这个函数返回某地址拥有的通证数量(account)。 该函数同样是一个取值函数,不会修改合约的状态。
function balanceOf(address account) external view returns (uint256);
allowance
此函数被用来查看owner给spender的通证额度。此函数是一个取值函数,不会修改合约的状态,并且默认应返回 0。
function allowance(address owner, address spender)externalviewreturns (uint256);
操作函数
transfer
将一定数量(amount)的通证从函数调用者地址(msg.sender)移动到接收者(to)地址。此函数发出稍后定义的Transfer事件。 如果可进行转账,它将返回 true,转账操作需要消耗gas。
function transfer(address to, uint256 amount) external returns (bool);
approve
函数调用方(msg.sender)可以调用这个函数授权spender代表它使用amount数量的通证,即设置允许spender从函数调用方(msg.sender)余额转账的allowance的数额。 此函数发出 Approval 事件。 此函数返回是否成功设置了余量。
function approve(address spender, uint256 amount) external returns (bool);
transferFrom
使用余量机制将通证的amount从from移动到to。 然后从调用者的余量中扣除该数额。 此函数发出Transfer事件。
function transferFrom(address from,address to,uint256 amount) external returns (bool);
事件
Transfer
将通证的数量value从from地址发送到to地址时会发出此事件,比如在调用 transfer 或 transferFrom 函数时。
event Transfer(address indexed from, address indexed to, uint256 value);
在铸造新的通证情况下,转账通常是 from 0x00…0000 地址,而在销毁通证的情况下,转账是 to 0x00…0000。
Approval
当owner批准要由spender使用的通证数量(value)时,将发出此事件。比如在调用 approve 函数时。
event Approval(address indexed owner,address indexed spender,uint256 value);
ERC-20 通证的基本实现
下面是 ERC-20 通证的最简单代码:
pragma solidity ^0.8.0;interface IERC20 {event Transfer(address indexed from, address indexed to, uint256 value);event Approval(address indexed owner,address indexed spender,uint256 value);function totalSupply() external view returns (uint256);function balanceOf(address account) external view returns (uint256);function allowance(address owner, address spender)externalviewreturns (uint256);function transfer(address to, uint256 amount) external returns (bool);function approve(address spender, uint256 amount) external returns (bool);function transferFrom(address from,address to,uint256 amount) external returns (bool);}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 view override returns (uint256) {return totalSupply_;}function balanceOf(address tokenOwner)publicviewoverridereturns (uint256){return balances[tokenOwner];}function transfer(address receiver, uint256 numTokens)publicoverridereturns (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)publicoverridereturns (bool){allowed[msg.sender][delegate] = numTokens;emit Approval(msg.sender, delegate, numTokens);return true;}function allowance(address owner, address delegate)publicviewoverridereturns (uint256){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;}}