以太坊代币标准ERC20、ERC165、ERC721

两个概念

  • 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

主要是指非同质化代币标准(不同人持有的一个代币的价值不一样,如,艺术品)

猜你喜欢

转载自blog.csdn.net/qxjswl/article/details/130372624