ERC20解读

Confucian 2022-04-04 22:20:20 阅读数:574

解读 erc20 erc blockchain learnblockchain

ERC20解读

参考 OpenZepplin文档以太坊官方开发者文档,结合自己的理解。

什么是ERC20

ERC20(Ethereum Request for Comments 20)一种代币标准。它具有一些典型功能。

ERC20 代币合约跟踪可替代代币:任何一个代币都完全等同于任何其他代币;没有任何代币具有与之相关的特殊权利或行为。这使得 ERC20 代币可用于交换货币、投票权、质押等媒介。

为什么要遵守ERC20

以太坊上的所有应用都默认支持 ERC20 ,如果你想自己发币,那么你的代码必须遵循 ERC20 标准,这样钱包(如MetaMask)等应用才能将你的币显示出来。

代码实现

需要实现以下函数和事件:

function name() public view returns (string)function symbol() public view returns (string)function decimals() public view returns (uint8)function totalSupply() public view returns (uint256)function balanceOf(address _owner) public view returns (uint256 balance)function transfer(address _to, uint256 _value) public returns (bool success)function transferFrom(address _from, address _to, uint256 _value) public returns (bool success)function approve(address _spender, uint256 _value) public returns (bool success)function allowance(address _owner, address _spender) public view returns (uint256 remaining)event Transfer(address indexed _from, address indexed _to, uint256 _value)event Approval(address indexed _owner, address indexed _spender, uint256 _value)

使用 OpenZeppllin 提供的库能够轻松快速地构建 ERC20 Token 。

快速构建

这是一个 GLD token 。

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

通常,我们定义代币的发行量和代币名称及符号。

IERC20

先来看下 ERC20 的接口(IERC20),这方便我们在开发中直接定义 ERC20 代币。

同样地,OpenZepplin 为我们提供了相应的库,方便开发者导入即用。

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

EIP 中定义的 ERC20 标准接口:

pragma solidity ^0.8.0;interface IERC20 { event Transfer(address indexed from, address indexed to, uint256 value); event Approval(address indexed owner, address indexed spender, uint256 value); function totalSupply() external view returns (uint256); function balanceOf(address account) external view returns (uint256); function transfer(address to, uint256 amount) external returns (bool); function allowance(address owner, address spender) external view returns (uint256); function approve(address spender, uint256 amount) external returns (bool); function transferFrom( address from, address to, uint256 amount ) external returns (bool);}

逐一分析

函数:

  • totalSupply() :返回总共的代币数量。
  • balanceOf(address account) :返回 account 地址拥有的代币数量。
  • transfer(address to, uint256 amount) :将 amount 数量的代币发送给 to 地址,返回布尔值告知是否执行成功。触发 Transfer 事件。
  • allowance(address owner, address spender) :返回授权花费者 spender 通过 transferFrom 代表所有者花费的剩余代币数量。默认情况下为零。当 approvetransferFrom 被调用时,值将改变。
  • approve(address spender, uint256 amount) :授权 spender 可以花费 amount 数量的代币,返回布尔值告知是否执行成功。触发 Approval 事件。
  • transferFrom(address from, address to, uint256 amount) :将 amount 数量的代币从 from 地址发送到 to 地址,返回布尔值告知是否执行成功。触发 Transfer 事件。

事件(定义中的 indexed 便于查找过滤):

  • Transfer(address from, address to, uint256 value) :当代币被一个地址转移到另一个地址时触发。注意:转移的值可能是 0 。
  • Approval(address owner, address spender, uint256 value) :当代币所有者授权别人使用代币时触发,即调用 approve 方法。

元数据

一般除了上述必须实现的函数外,还有一些别的方法:

  • name() :返回代币名称
  • symbol() :返回代币符号
  • decimals() 返回代币小数点后位数

ERC20

来看下 ERC20 代币具体是怎么写的。

同样,OpenZepplin 提供了现成的合约代码:

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

这里贴一个GitHub源码链接 OpenZepplin ERC20

函数概览

constructor(name_, symbol_)name()symbol()decimals()totalSupply()balanceOf(account)transfer(to, amount)allowance(owner, spender)approve(spender, amount)transferFrom(from, to, amount)increaseAllowance(spender, addedValue)decreaseAllowance(spender, subtractedValue)_transfer(from, to, amount)_mint(account, amount)_burn(account, amount)_approve(owner, spender, amount)_spendAllowance(owner, spender, amount)_beforeTokenTransfer(from, to, amount)_afterTokenTransfer(from, to, amount)

事件(同 IERC20)

Transfer(from, to, value)Approval(owner, spender, value)

逐一分析

  • constructor(string name, string symbol) :设定代币的名称和符号。decimals 默认是 18 ,要修改成不同的值你应该重载它。这两个值是不变的,只在构造时赋值一次。
  • name() :返回代币的名称。
  • symbol() :返回代币的符号,通常是名称的缩写。
  • decimals() :返回小数点后位数,通常是 18 ,模仿 Ether 和 wei 。要更改就重写它。

totalSupply()、balanceOf(address account)、transfer(address to, uint256 amount)、 allowance(address owner, address spender)、approve(address spender, uint256 amount)、transferFrom(address from, address to, uint256 amount) 都参考 IERC20 。

  • increaseAllowance(address spender, uint256 addedValue) :以原子的方式增加 spender 额度。返回布尔值告知是否执行成功,触发 Approval 事件。
  • _transfer(address from, address to, uint256 amount) :转账。这个内部函数相当于 transfer ,可以用于例如实施自动代币费用,削减机制等。触发 Transfer 事件。
  • _mint(address account, uint256 amount) :铸造 amount 数量的代币给 account 地址,增加总发行量。触发 Transfer 事件,其中参数 from 是零地址。
  • _burn(address account, uint256 amount) :从 account 地址中烧毁 amount 数量的代币,减少总发行量。触发 Transfer 事件,其中参数 to 是零地址。
  • _approve(address owner, uint256 spender, uint256 amount) :设定允许 spender 花费 owner 的代币数量。这个内部函数相当于 approve ,可以用于例如为某些子系统设置自动限额等。
  • spendAllowance(address owner, address spender, uint256 amount) :花费 amount 数量的 owner 授权 spender 的代币。在无限 allowance 的情况下不更新 allowance 金额。如果没有足够的余量,则恢复。可能触发 Approval 事件。
  • _beforeTokenTransfer(address from, address to, uint256 amount) :在任何代币转账前的 Hook 。它包括铸币和烧毁。调用条件:

    • fromto 都不是零地址时,from 手里 amount 数量的代币将发送给 to
    • from 是零地址时,将给 to 铸造 amount 数量的代币。
    • to 是零地址时,from 手里 amount 数量的代币将被烧毁。
    • fromto 不能同时为零地址。
  • _afterTokenTransfer(address from, address to, uint256 amount) :在任何代币转账后的 Hook 。它包括铸币和烧毁。调用条件:

    • fromto 都不是零地址时,from 手里 amount 数量的代币将发送给 to
    • from 是零地址时,将给 to 铸造 amount 数量的代币。
    • to 是零地址时,from 手里 amount 数量的代币将被烧毁。
    • fromto 不能同时为零地址。

小结

ERC20 代码中的 _transfer_mint_burn_approve_spendAllowance_beforeTokenTransfer_afterTokenTransfer 都是 internal 函数(其余为 public ),也就是说它们只能被派生合约调用。

总结

ERC20 其实就是一种最常见的代币标准,它明确了代币的经典功能并规范了开发者所编写的 token 的代码,从而方便各种应用适配。

版权声明:本文为[Confucian]所创,转载请带上原文链接,感谢。 https://learnblockchain.cn/article/3836