代币标准--ERC20协议源码解析

  • Nolan
  • 更新于 2022-08-06 16:38
  • 阅读 3424

ERC20代币标准源码解析

什么是ERC20标准

ERC是Ethereum Request for Comments的首字母缩写。它就像技术文档,定义了适用于一群想要利用以太坊生态系统的开发者和用户的方法、行为、创新和研究。ERC-20介绍了在以太坊区块链上创建可互换代币的代币标准,在该协议下的相同的代币完全一致。

IERC20:ERC20的接口定义

/ SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.6.0) (token/ERC20/IERC20.sol)

pragma solidity ^0.8.0;
interface IERC20 {

Transfer事件

    // 定义Transfer事件,在发生交易转移时触发。Solidity event在 EVM 的日志记录功能之上提供了一个抽象。应用程序可以通过以太坊客户端的 RPC 接口订阅和监听这些事件
    event Transfer(address indexed from, address indexed to, uint256 value);

Approval事件

    // 定义Approval事件,在发生代币授权时触发该事件
    event Approval(address indexed owner, address indexed spender, uint256 value);

totalSupply函数

   // 获取当前代币的总供应量
    function totalSupply() external view returns (uint256);

balanceOf函数

   // 获取当前账户的代币余额
    function balanceOf(address account) external view returns (uint256);

transfer函数

   // 代币转移函数,将amount数量的代币转移到to地址
    function transfer(address to, uint256 amount) external returns (bool);

allowance函数

    //获取owner地址账号授权(approve方法进行授权)给spender地址的代币数量
    function allowance(address owner, address spender) external view returns (uint256);

approve函数

    // 授权给spender地址 amount数量的代币,spender账户可以转移该数量代币通过调用
    function approve(address spender, uint256 amount) external returns (bool);

transferFrom函数

    // 从from地址转移amounts数量到to地址
    function transferFrom(
        address from,
        address to,
        uint256 amount
    ) external returns (bool);
}

ERC20代币标准源码

// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.7.0) (token/ERC20/ERC20.sol)

pragma solidity ^0.8.0;

import "./IERC20.sol";
import "./extensions/IERC20Metadata.sol";
import "../../utils/Context.sol";
// 合约继承IERC20、Context、IERC20Metadata
contract ERC20 is Context, IERC20, IERC20Metadata {
// _balances用于存储地址与其对应的代币余额
    mapping(address => uint256) private _balances;
// _allowances用于保存from地址 授权给 to地址的代币数量
    mapping(address => mapping(address => uint256)) private _allowances;
// 代币总供应量
    uint256 private _totalSupply;
// 代币名称
    string private _name;
// 代币标志
    string private _symbol;
//  构造函数 初始化 name symbol
    constructor(string memory name_, string memory symbol_) {
        _name = name_;
        _symbol = symbol_;
    }

name函数

// 获取代币名称
    function name() public view virtual override returns (string memory) {
        return _name;
    }

symbol函数

// 获取代币标志
    function symbol() public view virtual override returns (string memory) {
        return _symbol;
    }

decimals函数

// 获取小数点位数
    function decimals() public view virtual override returns (uint8) {
        return 18;
    }

totalSupply函数

//获取代币总供应量
    function totalSupply() public view virtual override returns (uint256) {
        return _totalSupply;
    }

balanceOf函数

// 获取account地址的代币余额
    function balanceOf(address account) public view virtual override returns (uint256) {
        return _balances[account];
    }

transfer函数

// 转移amount数量的代币到to地址
    function transfer(address to, uint256 amount) public virtual override returns (bool) {
    // 获取函数调用者owner账户地址
        address owner = _msgSender();

   // 从owner地址转移amount代币到to地址
        _transfer(owner, to, amount);
        return true;
    }

allowance函数

// 获取owner对spender的授权的代币数量
    function allowance(address owner, address spender) public view virtual override returns (uint256) {
        return _allowances[owner][spender];
    }

approve函数

// 给spender地址授权amount数量代币
    function approve(address spender, uint256 amount) public virtual override returns (bool) {
    // 获取当前调用合约的账户地址
        address owner = _msgSender();

    // 将owner地址的amount数量代币授权给spender
        _approve(owner, spender, amount);
        return true;
    }

transferFrom函数

// 从from地址转移amount代币到to地址
    function transferFrom(
        address from,
        address to,
        uint256 amount
    ) public virtual override returns (bool) {
    // 获取当前合约调用者的地址
        address spender = _msgSender();

    // 将from地址授权给spender地址的代币数量减少amount
        _spendAllowance(from, spender, amount);

    // 从from地址转移amount数量代币到to地址
        _transfer(from, to, amount);
        return true;
    }

increaseAllowance函数

// 增加授权给spender的代币数量addedValue
    function increaseAllowance(address spender, uint256 addedValue) public virtual returns (bool) {
    // 获取当前调用合约的账号地址
        address owner = _msgSender();

    // 重新授权增加过后的代币数量从owner地址给spender地址
        _approve(owner, spender, allowance(owner, spender) + addedValue);
        return true;
    }

decreaseAllowance函数

// 减少授权给spender的代币数量subtractedValue
    function decreaseAllowance(address spender, uint256 subtractedValue) public virtual returns (bool) {
     // 获取当前调用合约的账号地址
        address owner = _msgSender();

     // 获取当前owner授权给spender代币数量
        uint256 currentAllowance = allowance(owner, spender);

     // 检查 当前以授权代币数量 currentAllowance 是否大于等于subtractedValue
        require(currentAllowance >= subtractedValue, "ERC20: decreased allowance below zero");
   // 重新授权减少过后的代币数量从owner地址给spender地址
   // unchecked 关闭默认的溢出检查check,可以较少gas费
        unchecked {
            _approve(owner, spender, currentAllowance - subtractedValue);
        }

        return true;
    }

_transfer函数

    // 转移amount数量代币从from地址到to地址
    function _transfer(
        address from,
        address to,
        uint256 amount
    ) internal virtual {
        // 检查 from地址是否为空地址
        require(from != address(0), "ERC20: transfer from the zero address");

       // 检查 to地址不为空地址
        require(to != address(0), "ERC20: transfer to the zero address");

         //  转移前调用的函数 
        _beforeTokenTransfer(from, to, amount);

        // 获取from账户余额
        uint256 fromBalance = _balances[from];

        //检查账户余额 fromBalance 是否大于 要转移的代币数量amount
        require(fromBalance >= amount, "ERC20: transfer amount exceeds balance");

        unchecked {
        // 增加from地址代币数量
            _balances[from] = fromBalance - amount;
         // 增加to地址代币数量
            _balances[to] += amount;
        }
        // 触发Transfer事件 记录转移事件
        emit Transfer(from, to, amount);
        // 转移代币之后定义的函数
        _afterTokenTransfer(from, to, amount);
    }

_mint 函数

// 铸造新代币 并将代币转移到account地址
    function _mint(address account, uint256 amount) internal virtual {
    // 检查 account 是否为空地址
        require(account != address(0), "ERC20: mint to the zero address");

    // 转移代币前定义的函数
        _beforeTokenTransfer(address(0), account, amount);

    // 增加总供应量
        _totalSupply += amount;

        unchecked {
           // 增加account地址代币余额
            _balances[account] += amount;
        }
        // 触发代币转移事件,记录代币转移信息
        emit Transfer(address(0), account, amount);
       // 转移代币之后定义的函数
        _afterTokenTransfer(address(0), account, amount);
    }

_burn 函数

    // 销毁account账户amount数量的代币
    function _burn(address account, uint256 amount) internal virtual {
        // 检查地址不为空
        require(account != address(0), "ERC20: burn from the zero address");
         // 转移代币前定义的函数
        _beforeTokenTransfer(account, address(0), amount);

        //获取地址代币余额
        uint256 accountBalance = _balances[account];

        //检查地址代币余额 是否大于等于 要销毁的数量
        require(accountBalance >= amount, "ERC20: burn amount exceeds balance");
        unchecked {
            // 减少账户余额
            _balances[account] = accountBalance - amount;
            // 减少总供应量
            _totalSupply -= amount;
        }

        // 触发代币转移事件,记录代币转移信息
        emit Transfer(account, address(0), amount);
         // 转移代币之后定义的函数
        _afterTokenTransfer(account, address(0), amount);
    }

_approve函数

    // 将owner的代币授权给spender
    function _approve(
        address owner,
        address spender,
        uint256 amount
    ) internal virtual {
     // 检查地址不为空
        require(owner != address(0), "ERC20: approve from the zero address");
     // 检查地址不为空
        require(spender != address(0), "ERC20: approve to the zero address");
    // 授权amount数量代币
        _allowances[owner][spender] = amount;

       // 触发代币授权事件,记录代币授权信息
        emit Approval(owner, spender, amount);
    }

_spendAllowance函数

    // 将授权的的代币数量减少amout,用在transfer函数内调用
    function _spendAllowance(
        address owner,
        address spender,
        uint256 amount
    ) internal virtual {
    // 获取当前授权代币数量
        uint256 currentAllowance = allowance(owner, spender);
    // 判断当前代币数量是否等于uint256代币最大值
        if (currentAllowance != type(uint256).max) {
        // 检查 授权代币余额是否大于减少的代币数量
            require(currentAllowance >= amount, "ERC20: insufficient allowance");
            unchecked {
            // 减少代币授权数量
                _approve(owner, spender, currentAllowance - amount);
            }
        }
    }

_beforeTokenTransfer函数

// 在转移代币发生前的函数,包含mint 和 burn
    function _beforeTokenTransfer(
        address from,
        address to,
        uint256 amount
    ) internal virtual {}

_afterTokenTransfer函数

// 在转移代币发生后的函数,包含mint 和 burn
    function _afterTokenTransfer(
        address from,
        address to,
        uint256 amount
    ) internal virtual {}
}
点赞 0
收藏 2
分享
本文参与登链社区写作激励计划 ,好文好收益,欢迎正在阅读的你也加入。

0 条评论

请先 登录 后评论
Nolan
Nolan
江湖只有他的大名,没有他的介绍。