# ERC-20

By [Bob](https://paragraph.com/@bob-25) · 2024-11-24

---

**什么是 ERC-20？**
---------------

ERC-20 提出了一个同质化代币的标准，换句话说，它们具有一种属性，使得每个代币都与另一个代币（在类型和价值上）完全相同。 例如，一个 ERC-20 代币就像以太币一样，意味着一个代币会并永远会与其他代币一样。(From: 《[ERC-20 代币标准](https://ethereum.org/zh/developers/docs/standards/tokens/erc-20/)》)

### 方法（Method）

    function name() public view returns (string)
    // 返回令牌的名称 - 例如 "MyToken"
    // 可选 - 此方法可用于提高可用性，但接口和其他协定不得期望存在这些值。
    
    function symbol() public view returns (string)
    // 返回令牌的 symbol。例如“HIX”。
    // 可选 - 此方法可用于提高可用性，但接口和其他协定不得期望存在这些值。
    
    function decimals() public view returns (uint8)
    // 返回代币使用的小数位数 - 例如 8，表示将代币数量除以 100000000 以获得其用户表示。
    // 可选 - 此方法可用于提高可用性，但接口和其他协定不得期望存在这些值。
    
    function totalSupply() public view returns (uint256)
    // 返回总代币供应量。
    
    function balanceOf(address _owner) public view returns (uint256 balance)
    // 返回地址为 _owner 的另一个账户的账户余额。
    
    function transfer(address _to, uint256 _value) public returns (bool success)
    // 将 _value 数量的代币转移到 _to，并且必须触发 Transfer 事件。如果消息调用者的账户余额没有足够的代币可供花费，则函数应该throw。
    // 注意值为 0 的传输必须被视为正常传输，并触发 Transfer 事件。
    
    function transferFrom(address _from, address _to, uint256 _value) public returns (bool success)
    // 将 _value数量的代币从地址 _from 转移到地址 _to，并且必须触发 Transfer 事件。
    // transferFrom 方法用于提现工作流程，允许合约代表您转移代币。例如，这可用于允许合约代表您转移代币和/或以子货币收取费用。除非 _from 账户通过某种机制故意授权了消息的发送者，否则该函数应该throw。
    
    function approve(address _spender, uint256 _value) public returns (bool success)
    // 允许_spender多次从您的账户提款，最高可达_value金额。如果再次调用此函数，它将用 _value 覆盖当前限额。
    // 注意：客户端应该确保在创建用户界面时，先将限额设置为 0，然后再为同一花费者将其设置为另一个值。尽管 Contract 本身不应该强制执行它，以允许向后兼容之前部署的 Contract
    
    function allowance(address _owner, address _spender) public view returns (uint256 remaining)
    // 返回 _spender 仍允许从 _owner 中提取的金额。
    

### 事件（Event）

    event Transfer(address indexed _from, address indexed _to, uint256 _value)
    // 必须在代币转移时触发，包括零价值转移。
    // 创建新代币的代币合约应该在创建代币时触发 Transfer 事件，并将 _from 地址设置为 0x0。
    
    event Approval(address indexed _owner, address indexed _spender, uint256 _value)
    // 必须在成功调用 approve(address _spender, uint256 _value) 时触发。
    

实现
--

### 简单示例

    // SPDX-License-Identifier: MIT
    
    pragma solidity ^0.8.0;
    
    contract MyToken {
        string public constant name = "Bob's Token";
        string public constant symbol = "BBK";
        uint8 public constant decimals = 18;
        uint16 private constant increase = 1000;
        uint256 public constant totalLimit = 27000000 * (10 ** decimals);
        uint256 public totalSupply = 0;
        address private owner;
        mapping(address => uint256) public balanceOf;
        mapping(address => mapping(address => uint256)) public allowance;
    
        event Transfer(address indexed _from, address indexed _to, uint256 _value);
        event Approval(address indexed _owner, address indexed _spender, uint256 _value);
    
        modifier checkAddress(address _addr) {
            require(address(_addr) != address(0), "Invalid address.");
            _;
        }
    
        modifier checkBalanceOf(address _addr, uint256 _value) {
            require(balanceOf[_addr] >= _value, "Insufficient balance");
            _;
        }
    
        modifier checkOwner() {
            require(msg.sender == owner, "Not owner.");
            _;
        }
    
        constructor() {
            owner = msg.sender;
        }
    
        function mint(address _to) public checkOwner returns (uint256) {
            uint256 mintValue = increase * (10  ** decimals);
            require(totalLimit < (totalSupply + mintValue), "Out of limit.");
            totalSupply += mintValue;
            balanceOf[_to] += mintValue;
            return balanceOf[_to];
        }
    
        function transfer(address _to, uint256 _value) public checkAddress(_to) checkBalanceOf(msg.sender, _value) returns (bool success){
            balanceOf[msg.sender] -= _value;
            balanceOf[_to] += _value;
            emit Transfer(msg.sender, _to, _value);
            return true;
        }
    
        function transferFrom(address _from, address _to, uint256 _value) public checkAddress(_to) checkBalanceOf(_from, _value) returns (bool success) {
            require(allowance[_from][msg.sender] >= _value, "No enough approve value.");
            allowance[_from][msg.sender] -= _value;
            balanceOf[_from] -= _value;
            balanceOf[_to] += _value;
            emit Transfer(_from, _to, _value);
            return true;
        }
    
        function approve(address _spender, uint256 _value) public returns (bool success){
            allowance[msg.sender][_spender] = _value;
            emit Approval(msg.sender, _spender, _value);
            return true;
        }
    }
    

**注意事项**

*   由于本合约的编译版本为0.8.0，此版本具备整数溢出检查，所以可以不使用safeMath。
    

### 快速示例

使用Open zeppelin快速创建ERC-20合约

    // SPDX-License-Identifier: MIT
    pragma solidity ^0.8.20;
    
    import {ERC20} from "@openzeppelin/contracts/token/ERC20/ERC20.sol";
    
    contract GLDToken is ERC20 {
        constructor(uint256 initialSupply) ERC20("Gold", "GLD") {
            _mint(msg.sender, initialSupply);
        }
    }
    

       我们的合约通常通过[继承](https://solidity.readthedocs.io/en/latest/contracts.html#inheritance)来使用，在这里我们将 `ERC20` 重新用于基本标准实现以及 `name`、`symbol` 和 `decimals` 可选扩展。此外，我们正在创建一个代币的 `initialSupply`，该代币将被分配给部署合约的地址。(From: 《[ERC-20]()》)

---

*Originally published on [Bob](https://paragraph.com/@bob-25/erc-20)*
