Erc20

ERC20 #

ERC20 是以太坊上的代币标准,来自2015年11月V神参与的 EIP20。你可以把实现了 ERC20 的智能合约理解为区块链上的一家银行。我们去银行办的业务无非就是查询账户余额、转账等。ERC20 就定义了区块链上的一家银行应该具备哪些能力。

如果你要在区块链上开一家 ERC20 银行,那么你的银行需要有以下业务能力:

  • 查询代币总供给(totalSupply())
  • 查询账户余额(balanceOf())
  • 转账(transfer())
  • 授权(approve())
  • 查询授权转账额度(allowance())
  • 授权转账(transferFrom())
  • 代币信息(可选):名称(name()),代号(symbol()),小数位数(decimals())

IERC20 #

IERC20ERC20代币标准的接口合约,规定了ERC20代币需要实现的函数和事件。 之所以需要定义接口,是因为有了规范后,就存在所有的ERC20代币都通用的函数名称,输入参数,输出参数。 在接口函数中,只需要定义函数名称,输入参数,输出参数,并不关心函数内部如何实现。 由此,函数就分为内部和外部两个内容,一个重点是实现,另一个是对外接口,约定共同数据。 这就是为什么需要ERC20.solIERC20.sol两个文件实现一个合约。

事件 #

IERC20定义了2个事件:Transfer事件和Approval事件,分别在转账和授权时被释放。

/**
 * @dev 释放条件:当 `value` 单位的货币从账户 (`from`) 转账到另一账户 (`to`)时.
 */
event Transfer(address indexed from, address indexed to, uint256 value);

/**
 * @dev 释放条件:当 `value` 单位的货币从账户 (`owner`) 授权给另一账户 (`spender`)时.
 */
event Approval(address indexed owner, address indexed spender, uint256 value);

函数 #

IERC20定义了6个函数,提供了转移代币的基本功能,并允许代币获得批准,以便其他链上第三方使用。

/**
 * @dev 返回代币总供给.
 */
function totalSupply() external view returns (uint256);

/**
 * @dev 返回账户`account`所持有的代币数.
 */
function balanceOf(address account) external view returns (uint256);

/**
* @dev 转账`amount`单位代币,从调用者账户到另一账户`to`
* 如果成功,返回 `true`
* 释放 {Transfer} 事件
*/
function transfer(address to, uint256 amount) external view returns (bool);

/**
* @dev 调用者账户向`spender`授权`amount`单位代币
* 如果成功,返回 `true`
* 释放 {Approval} 事件
*/
function approve(address spender, uint256 amount) external view returns (bool);

/**
* @dev 返回`owner`向`spender`授权的额度
*/
function allowance(address owner, address spender) external view returns (uint256);

/**
* @dev 从`from`账户向`to`账户转账`amount`单位代币
* 需要满足`from`已经向`to`账户授权超过`amount`单位代币
* 如果成功,`from`向`to`的`allowance`会扣除相应的额度,并返回`true`
*/
function transferFrom(address from, address to, uint256 amount) external view returns (bool);

实现 ERC20 #

// SPDX-License-Identifier: MIT
pragma solidity ^0.8.26;

import "@openzeppelin/contracts/token/ERC20/IERC20.sol";

contract MyCoin is IERC20 {
	string public name; // 名称 可选
	string public symbol; // 代号 可选
	uint8 public decimals = 18; // 小数位数 可选
	
	/**
	* 构造函数,初始化代币名称和代号
	*/
	constructor(string memory _name, string memory _symbol) {
		name = _name;
		symbol = _symbol;
	}
	
	// 代币总供给
    uint256 public override totalSupply = 500;
    // 账户-余额映射表
    mapping(address => uint256) public override balanceOf;
    // 账户-账户-授权额度映射表
    mapping(address => mapping(address => uint256)) public override allowance;

	/**
    * @dev 转账`value`单位代币,从调用者账户到另一账户`to`
    * 如果成功,返回 `true`
    * 释放 {Transfer} 事件
    */
    function transfer(address to, uint256 value) external override returns (bool) {
        require(balanceOf[msg.sender] >= value);
        balanceOf[msg.sender] -= value;
        balanceOf[to] += value;
        emit Transfer(msg.sender, to, value);
        return true;
    }

    /**
    * @dev 调用者账户向`spender`授权`amount`单位代币
    * 如果成功,返回 `true`
    * 释放 {Approval} 事件
    */
    function approve(address spender, uint256 amount) external override returns (bool) {
        allowance[msg.sender][spender] += amount;
        emit Approval(msg.sender, spender, amount);
        return true;
    }

	/**
    * @dev 从`owner`账户向`spender`账户转账`amount`单位代币
    * 需要满足`owner`已经向`spender`账户授权超过`amount`单位代币
    * 如果成功,`owner`向`spender`的`allowance`会扣除相应的额度,并返回`true`
    */
    function transferFrom(address owner, address spender, uint256 amount) external override returns (bool) {
        require(allowance[owner][spender] >= amount);
        require(balanceOf[owner] >= amount);
        allowance[owner][spender] -= amount;
        balanceOf[owner] -= amount;
        balanceOf[spender] += amount;
        emit Transfer(owner, spender, amount);
        return true;
    }
    
    
}