两个概念
- ERC(Ethereum Request for Comment) 以太坊意见征集稿
- EIP(Ethereum Improvement Proposals)以太坊改进提案
ERC和EIP用于使得以太坊更加完善;在ERC中提出了很多标准,用的最多的标准就是它的Token标准;
有哪些标准详细见https://eips.ethereum.org/erc
常见ERC标准
ERC-20 | Token Standard |
---|---|
ERC-721 | Non-Fungible Token Standard |
ERC-165 | Standard Interface Detection |
ERC-777 | Token Standard |
ERC-1155 | Multi Token Standard |
ERC-20
主要是指同质化代币标准(不同人持有的一个代币是等值的)。
ERC-20标准中主要有6个函数和两个事件
其中这6个函数表达的意义是:
totalSupply:总发行量
balanceOf:账户余额
transfer:转账
transferFrom:针对授权进行转账
approve:授权
allowance:owner授权给spender余额
具体的详细见https://eips.ethereum.org/EIPS/eip-20
实现ERC20标准代币
想要发现ERC20标准的代币,就需要实现ERC20标准接口中的函数
先写ERC20标准接口
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;
interface IERC20 {
function name() external view returns (string memory);
function symbol() external view returns (string memory);
function decimals() external view returns (uint8);
function totalSupply() external view returns (uint256);
function balanceOf(address _owner) external view returns (uint256 balance);
function transfer(address _to, uint256 _value) external returns (bool success);
function transferFrom(address _from, address _to, uint256 _value) external returns (bool success);
function approve(address _spender, uint256 _value) external returns (bool success);
function allowance(address _owner, address _spender) external view returns (uint256 remaining);
//_from和_to两个参数有indexed关键字修饰,表示这些参数可以作为过滤条件来搜索事件。
event Transfer(address indexed _from, address indexed _to, uint256 _value);
event Approval(address indexed _owner, address indexed _spender, uint256 _value);
}
再实现ERC20标准代币
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;
import "./IERC20.sol";
contract ERC20 is IERC20{
string ercName;
string ercSymbol;
uint8 ercDecimals;
uint256 ercTotalSupply;
mapping(address=>uint256) ercBalances;
//一个人可以有多个委托人:授权者=>被授权者=>授权金额
mapping (address=>mapping (address=>uint256)) ercAllowance;
//合约部署者
address public owner;
constructor(string memory _name, string memory _symbol,uint8 _decimals){
ercName=_name;
ercSymbol=_symbol;
ercDecimals=_decimals;
owner=msg.sender;
}
//token名称
function name() override external view returns (string memory){
return ercName;
}
//token符号
function symbol() override external view returns (string memory){
return ercSymbol;
}
//token可以拆分到的精度
function decimals() override external view returns (uint8){
return ercDecimals;
}
//token发行总量
function totalSupply() override external view returns (uint256){
return ercTotalSupply;
}
//账户余额
function balanceOf(address _owner) override external view returns (uint256 balance){
return ercBalances[_owner];
}
//给某人转账
function transfer(address _to, uint256 _value) override external returns (bool success){
require(_value>0,"_value must >0");
require(_to!=address(0),"_to is null");
require(ercBalances[msg.sender]>=_value,"user's balance not enough");
ercBalances[msg.sender]-=_value;
ercBalances[_to]+=_value;
emit Transfer(msg.sender, _to, _value);
return true;
}
//被授权用户用我的token转账;_from: 授权者,_to:转给谁
function transferFrom(address _from, address _to, uint256 _value) override external returns (bool success){
require(ercBalances[_from] >= _value,"user's balance not enough");
require(ercAllowance[_from][msg.sender]>=_value,"approve's balance not enough");
require(_value>0,"_value must > 0");
require(_to!=address(0),"_to is null");
ercBalances[_from]-=_value;
ercBalances[_to]+=_value;
ercAllowance[_from][msg.sender]-=_value;
emit Transfer(_from, _to, _value);
return true;
}
//授权其他用户可以花费我多少token
function approve(address _spender, uint256 _value) override external returns (bool success){
// require(_value>0,"value must >0");//让_value可以等于0,当其为0时表示收回授权
require(_spender!=address(0),"_spender can not be null");
require(ercBalances[msg.sender]>=_value,"user's balance not enough");
ercAllowance[msg.sender][_spender]=_value;
emit Approval(msg.sender, _spender, _value);
return true;
}
//获取授花费的余额token
function allowance(address _owner, address _spender) override external view returns (uint256 remaining){
return ercAllowance[_owner][_spender];
}
//代币发行机制
function mint(address _to,uint256 _value) public{
require(msg.sender==owner,"only owner can mint");
require(_value>0,"_value must > 0");
require(_to!=address(0),"_to is invalid");
ercBalances[_to]+=_value;
ercTotalSupply+=_value;
emit Transfer(address(0), _to, _value);
}
}
ERC165
是一个标准接口检测的标准;用于检测合约是否符合规范
注意:函数选择器:
函数参数只保留类型,计算 hash("函数名(类型1, 类型2, ...)"),并取哈希结果的前4个字节
举例,如下函数的函数选择器是:计算hash(“Transfer(address,uint256)”),并取哈希结果的前4个字节
function Transfer(address to,uint256 value){
//函数体
}
注意:接口ID:
将一个接口里面的所有函数选择器做异或处理,得到接口的ID
如何判断一个接口支持了ERC165?
ERC-721
主要是指非同质化代币标准(不同人持有的一个代币的价值不一样,如,艺术品)