Solidity 合约分析:4. ERC20

介绍

你好,我是 Pluveto。我发现多数 Solidity 的教程都是从语法开始讲起,但是我觉得这样不够直观,而且很消耗耐心。这是一个系列文章,我会在这个系列里分析一些简单的 Solidity 合约。在例子中学习。

希望你能学到东西,让我们开始吧!

代码

ERC20 | Solidity by Example | 0.8.20

 1// SPDX-License-Identifier: MIT
 2pragma solidity ^0.8.20;
 3
 4// https://github.com/OpenZeppelin/openzeppelin-contracts/blob/v3.0.0/contracts/token/ERC20/IERC20.sol
 5interface IERC20 {
 6    function totalSupply() external view returns (uint);
 7
 8    function balanceOf(address account) external view returns (uint);
 9
10    function transfer(address recipient, uint amount) external returns (bool);
11
12    function allowance(address owner, address spender) external view returns (uint);
13
14    function approve(address spender, uint amount) external returns (bool);
15
16    function transferFrom(
17        address sender,
18        address recipient,
19        uint amount
20    ) external returns (bool);
21
22    event Transfer(address indexed from, address indexed to, uint value);
23    event Approval(address indexed owner, address indexed spender, uint value);
24}
 1// SPDX-License-Identifier: MIT
 2pragma solidity ^0.8.20;
 3
 4import "./IERC20.sol";
 5
 6contract ERC20 is IERC20 {
 7    uint public totalSupply;
 8    mapping(address => uint) public balanceOf;
 9    mapping(address => mapping(address => uint)) public allowance;
10    string public name = "Solidity by Example";
11    string public symbol = "SOLBYEX";
12    uint8 public decimals = 18;
13
14    function transfer(address recipient, uint amount) external returns (bool) {
15        balanceOf[msg.sender] -= amount;
16        balanceOf[recipient] += amount;
17        emit Transfer(msg.sender, recipient, amount);
18        return true;
19    }
20
21    function approve(address spender, uint amount) external returns (bool) {
22        allowance[msg.sender][spender] = amount;
23        emit Approval(msg.sender, spender, amount);
24        return true;
25    }
26
27    function transferFrom(
28        address sender,
29        address recipient,
30        uint amount
31    ) external returns (bool) {
32        allowance[sender][msg.sender] -= amount;
33        balanceOf[sender] -= amount;
34        balanceOf[recipient] += amount;
35        emit Transfer(sender, recipient, amount);
36        return true;
37    }
38
39    function mint(uint amount) external {
40        balanceOf[msg.sender] += amount;
41        totalSupply += amount;
42        emit Transfer(address(0), msg.sender, amount);
43    }
44
45    function burn(uint amount) external {
46        balanceOf[msg.sender] -= amount;
47        totalSupply -= amount;
48        emit Transfer(msg.sender, address(0), amount);
49    }
50}

ERC20 让每个人都能创建和转移代币。

interface 关键字在 Solidity 中定义接口合约。

接口合约主要为了标识合约应该实现的功能,区别于 library 和 contract:

  • 使用 interface 定义接口合约。

  • 接口合约只能定义函数签名,不可以定义实现函数体。

  • 接口合约中的函数都是外部函数,默认是 public 的。

  • 普通合约可以实现一个或多个接口,需要实现接口声明的所有函数。

interface IERC20 要求实现以下函数:

  1. totalSupply() 返回代币总量。

  2. balanceOf(address account) 返回指定账户的代币余额。

  3. transfer(address recipient, uint amount) 转移代币到指定账户。

  4. allowance(address owner, address spender) 返回 owner 授权给 spender 的代币数量。

  5. approve(address spender, uint amount) 授权 spender 可以转移 amount 个代币。

  6. transferFrom(address sender, address recipient, uint amount) 从 sender 转移 amount 个代币到 recipient。

同时,还定义了两个事件:

  1. Transfer 代币转移事件。

  2. Approval 授权事件。

然后我们来看具体实现。

  1. transfer:直接更新余额,然后触发 Transfer 事件。由于 balance 是 uint 类型,所以不需要考虑溢出。

  2. approve 直接通过更新 allowance 实现,然后触发 Approval 事件。

  3. transferFrom:先更新 allowance,然后更新余额,最后触发 Transfer 事件。

  4. mint:增发代币,然后触发 Transfer 事件。

  5. burn:销毁代币,然后触发 Transfer 事件。

其他方法示例里没有完全实现。