ERC20

225 阅读3分钟

一、EIP

全称Ethereum Improvement Proposal,Ethereum改进提案,是对以太坊网络的功能、协议或规范进行改进的提案文档。

EIP可以在Ethereum 生态中任意领域 提出改进意见,比如新特性、ERC、协议改进、编程工具等等。

image.png

二、ERC

全称Ethereum Request for Comments,以太坊请求评论,是对以太坊网络上的特定标准或协议进行规范化的提案文档。ERC通常涉及以太坊智能合约的标准和接口,以促进不同智能合约之间的互操作性。ERC可以被认为是以太坊的标准化提案。

1) 生命周期
  • ERC 和 EIP 都有4个阶段:

      1. Draft:草稿,处于讨论状态的提案。
      1. Accept:接受,可能在下一个块或分叉中生效。
      1. Final:定稿。已经生效的,比如ERC20,ERC721等。
      1. Deffered:延期,不会马上被接受,也许在将来被接受。
  • ERC 和 EIP 的关系

    • 所有的ERC都是EIP。

三、ERC20

ERC20 标准只包括接口,并非指标准的代码,而是只要满足了ERC20的接口,你接口包含ERC20 所列出的所有的接口,就代表你满足了ERC20的标准。至于合约中的方法是如何实现的并不关心,合约逻辑如何实现没有强制要求。

ERC20: 同质化代币,意味着每个代币的价值和性质是相同的,可以互换。

Code

// SPDX-License-Identifier: MIT  
  
pragma solidity >=0.8.20;  
  
interface IERC20 {  
  
    // token总量  
    function totalSupply() external view returns (uint); // 函数可见性声明:在 interface 中,不需要明确标注函数为 public,默认是 external。不过在实现合约中需要明确标注函数的可见性。  
  
    // 某一个账户当前余额  
    function balanceOf(address _owner) external view returns (uint balance);  
  
    // 转账  
    // params 将 _value数量的代币 转移到 地址_to  
    function transfer(address _to, uint _value) external returns (bool success);  
    // params 将 _value数量的代币 从 地址_from 转移到 地址_to  
    function transferFrom(address _from, address _to, uint _value) external returns (bool success);  
  
    // params 允许 _spender 提取 _value数量的代币  
    function approve(address _spender, uint _value) external returns (bool success);  
  
    //params 检查 _spender 消费 _owner 代币数量  
    // returns 返回代币数量  
    function allowance(address _owner, address _spender) external view returns (uint remaining);  
  
    // 事件  
    // _from: 代币的发送者地址  
    // _to: 代币的接收者地址  
    // _value: 转移的代币数量  
    event Transfer(address indexed _from, address indexed _to, uint _value);  
    // _owner: 代币的所有者  
    // _spender: 被授权消费代币的账户地址  
    // _value:授权给_spender的代币数量  
    event Approval(address indexed _owner, address indexed _spender, uint _value);  
}  
  
  
contract ERC20 is IERC20 {  
  
    uint private _totalSupply; // 当前合约的token总量  
    mapping(address => uint) private _balances; // 账本:地址 => 余额  
  
    mapping(address => mapping(address => uint)) private _allowances; // 映射批准信息 _owner => ( _spender => _value )  
    // 这里必须使用override来标明此函数是重写自IERC20接口的  
    function totalSupply() external view override returns (uint) {  
        return _totalSupply;  
    }  
      
    function balanceOf(address _owner) external view override returns (uint balance) {  
        return _balances[_owner];  
    }  
  
    function transfer(address _to, uint _value) external override returns (bool success) {  
        require(_balances[msg.sender] >= _value, "Insufficient balance"); // 检查余额  
        require(_to != address(0), "Invalid recipient address"); // 检查地址是否为0地址  
        _balances[msg.sender] -= _value;  
        _balances[_to] += _value;  
        emit Transfer(msg.sender, _to, _value);  
        return true;    }  
      
    function transferFrom(address _from, address _to, uint _value) external override returns (bool success) {  
        require(_balances[_from] >= _value, "Insufficient balance"); // 检查 _from 的余额  
        require(_allowances[_from][msg.sender] >= _value, "Allowance exceeded"); // 检查授权额度  
        require(_to != address(0), "Invalid recipient address"); // 检查地址是否为0地址  
  
        _balances[_from] -= _value;  
        _balances[_to] += _value;  
        _allowances[_from][msg.sender] -= _value; // TODO 支持委托转账  
        emit Transfer(_from, _to, _value);  
        return true;    }  
  
  
    function approve(address _spender, uint _value) external override returns (bool success) {  
        require(_spender != address(0), "Invalid spender address"); // 检查地址是否为0地址  
  
        _allowances[msg.sender][_spender] = _value;  
        emit Approval(msg.sender, _spender, _value);  
        return true;    }  
  
  
    function allowance(address _owner, address _spender) external view override returns (uint remaining) {  
        return _allowances[_owner][_spender];  
    }  
  
}