两个概念
- 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
主要是指非同质化代币标准(不同人持有的一个代币的价值不一样,如,艺术品)



![[WUSTCTF2020]颜值成绩查询 布尔注入二分法](https://img-blog.csdnimg.cn/0592b587c5eb42c2b81108986f6cb789.png)















