Web3学习之 ERC20
Table of Contents
Web3学习之 ERC20
ERC20
ERC20 是以太坊上的一种代币标准,它定义了一组接口(方法和事件),使得代币可以在不同的应用程序、钱包和交易所之间进行互操作。ERC20 标准使得创建和使用代币变得简单和一致,是最广泛采用的代币标准之一。
EIP / ERC 标准
- 标准:降低沟通协作成本、增强互操作性
- EIP: Ethereum Improvement Proposal 以太坊改进提案
- 不是所有的 EIP 都是标准
- 提交改进 Issue (编号)、社区的讨论(实现及验证) 、形成共识、作为标准
EIP(Ethereum Improvement Proposal,以太坊改进提案)是以太坊社区提出和讨论对以太坊平台进行改进和变更的正式流程。EIP 分为几个主要分类,每个分类有不同的目的和用途。以下是 EIP 的主要分类:
-
核心(Core):
- 这些是影响以太坊核心协议的改进提案,包括共识协议更改、网络升级和硬分叉。
- Core EIP 是对以太坊的底层协议和运行机制的改进,需要进行广泛的测试和社区共识。
-
接口(Interface,ERC):
- 这些提案用于标准化以太坊上的应用程序接口(API)和智能合约标准。
- 最著名的例子是 ERC-20 标准,它定义了代币的接口,使代币在不同的应用程序和交易所之间具有互操作性。
-
网络(Networking):
- 涉及以太坊网络协议的改进提案,包括对节点间通信的更改。
- Networking EIP 包括对以太坊网络消息传递协议和数据传输的改进。
-
元(Meta):
- Meta EIP 涉及以太坊改进提案流程本身的改进,包括对 EIP 模板、格式和流程的更改。
- 这些提案不直接涉及以太坊代码或协议的更改,而是关于管理和协调改进提案的流程。
-
信息(Informational):
- 提供与以太坊设计和使用相关的指导和信息。
- 这些提案不提议任何新的功能或标准,只是为开发者和用户提供信息和最佳实践。
示例
- EIP-1:描述了 EIP 的流程和指南,属于 Meta 分类。
- EIP-20(ERC-20):定义了标准的代币接口,属于 Interface 分类。
- EIP-1559:对以太坊的交易费用结构进行改进,属于 Core 分类。
ERC20 标准提供了一组基础接口,使得代币可以在以太坊生态系统中方便地创建、管理和交换
区分原生币(Coin)和代币(Token)
你所提到的区别是区分原生币(Coin)和代币(Token)的关键概念。以下是更详细的解释:
以太币(Coin)
- 原生币: 以太币(Ether,ETH)是以太坊区块链的原生加密货币。它直接由区块链协议生成和管理。
- 用途: 主要用于支付网络上的交易费用(Gas)以及奖励矿工(现在是验证者)。
- 特性: 原生币的交易是直接在区块链上进行的,不需要任何智能合约。
- 地址: 以太币的交易地址是由以太坊协议生成的。
ERC20 代币(Token)
- 智能合约币: ERC20 代币是通过智能合约创建和管理的加密货币。它们不是区块链的原生币,而是构建在区块链之上的。
- 用途: 可以代表各种资产或功能,如稳定币、权益证明、治理代币等。
- 特性: ERC20 代币遵循以太坊改进提案 20(EIP-20)的标准,实现了一组基本的接口和功能,使其能够在去中心化应用(DApps)之间互操作。
- 地址: ERC20 代币的合约地址是由智能合约生成的。
WETH(Wrapped Ether)
- 包装以太币: WETH(Wrapped Ether)是将 ETH 包装成 ERC20 代币的形式,使其能够在需要 ERC20 标准的去中心化应用中使用。
- 用途: 由于 ETH 不是 ERC20 代币,有些 DApps 需要使用 ERC20 标准,因此 WETH 充当桥梁,使 ETH 可以像其他 ERC20 代币一样使用。
- 特性: 1 WETH 始终等于 1 ETH,用户可以随时在 WETH 和 ETH 之间转换。
- 合约地址: WETH 有自己的智能合约地址,用户通过该地址进行 WETH 与 ETH 的转换。
代码示例
以下是一个简单的将 ETH 转换为 WETH 的合约示例:
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;
interface IWETH {
function deposit() external payable;
function withdraw(uint256 wad) external;
}
contract ETHToWETH {
IWETH public weth;
constructor(address _weth) {
weth = IWETH(_weth);
}
function convertEthToWeth() external payable {
require(msg.value > 0, "Must send ETH to convert to WETH");
weth.deposit{value: msg.value}();
}
function convertWethToEth(uint256 amount) external {
require(amount > 0, "Must specify WETH amount to convert to ETH");
weth.withdraw(amount);
payable(msg.sender).transfer(amount);
}
receive() external payable {
revert("Send ETH directly to this contract is not allowed");
}
}
https://eips.ethereum.org/EIPS/eip-20
标准接口允许以太坊上的任何代币被其他应用程序重复使用:从钱包到去中心化交易所。
必备技能:不适用任何库的情况下,纯手撸ERC20
不要死记硬背
第一性原理
从区块链的角度出发实现一个数字货币一个链上的数字货币
思考:在技术层面需要什么接口
任何一个货币系统都有一个余额表,知道用户名是谁、余额是多少,在ERC20里面叫 balanceOf
它接收一个地址作为参数,返回这个地址的余额
知道总量是多少,在ERC20里面叫 total supply
用户之间需要转账,在ERC20里面叫 transfer
还有approve
、allowance
可以用于:
两个普通用户之间的一个约定,也可以用于一个普通用户和一个合约用户之间的一个约定。
例如 A 和 B ,其中A有1万元,但是它不想经常使用,因为没有很好的管理习惯,使用的越多,风险越大。所以A 新建了一个 B 账户,B 账户最多可以使用 A 账户中1万元的100块钱。
这就是 approve
、allowance
、transferFrom
所服务的一个场景
6 + 3 + 2
6 个必备的方法
3个可选的方法
2个必备的事件
思考:获取 USDT 合约的所有地址和地址的持币数量
通过事件获取合约的所有持币地址
https://etherscan.io/token/0xdac17f958d2ee523a2206206994597c13d831ec7#balances
ERC20 还有很多插件:mint 、burn …
https://github.com/OpenZeppelin/openzeppelin-contracts/tree/master/contracts/token/ERC20
USDT的合约的坑
以太坊 USDT 没有完全遵循 ERC20 标准,它transfer没有返回值
ERC20标准
USDT 的实现
USDT合约代码
参考:
- https://learnblockchain.cn/article/506
- https://ethereum.stackexchange.com/questions/144368/unable-to-use-usdt-token-inside-contract
解决
1 安装USDT 修改你的 interface
2 使用 SafeERC20
实现一个简单的ERC20
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;
contract BaseERC20 {
string public name;
string public symbol;
uint8 public decimals;
uint256 public totalSupply;
mapping(address => uint256) balances;
mapping(address => mapping(address => uint256)) allowances;
event Transfer(address indexed from, address indexed to, uint256 value);
event Approval(address indexed owner, address indexed spender, uint256 value);
constructor() {
// 设置代币的名称、符号、小数位数和总供应量
name = "BaseERC20";
symbol = "BERC20";
decimals = 18;
totalSupply = 100000000 * (10 ** uint256(decimals));
// 初始供应量分配给合约部署者
balances[msg.sender] = totalSupply;
}
function balanceOf(address _owner) public view returns (uint256 balance) {
return balances[_owner];
}
function transfer(address _to, uint256 _value) public returns (bool success) {
require(balances[msg.sender] >= _value && _value > 0, "ERC20: transfer amount exceeds balance");
require(_to != address(0), "ERC20: transfer to the zero address");
unchecked {
balances[msg.sender] -= _value;
}
unchecked {
balances[_to] += _value;
}
emit Transfer(msg.sender, _to, _value);
return true;
}
function transferFrom(address _from, address _to, uint256 _value) public returns (bool success) {
require(balances[_from] >= _value && _value > 0, "ERC20: transfer amount exceeds balance");
require(_to != address(0), "ERC20: transfer to the zero address");
require(allowances[_from][msg.sender] >= _value, "ERC20: transfer amount exceeds allowance");
unchecked {
balances[_from] -= _value;
}
unchecked {
balances[_to] += _value;
}
unchecked {
allowances[_from][msg.sender] -= _value;
}
emit Transfer(_from, _to, _value);
return true;
}
function approve(address _spender, uint256 _value) public returns (bool success) {
require(_spender != address(0), "ERC20: approve to the zero address");
allowances[msg.sender][_spender] = _value;
emit Approval(msg.sender, _spender, _value);
return true;
}
function allowance(address _owner, address _spender) public view returns (uint256 remaining) {
return allowances[_owner][_spender];
}
}
注意:实际一般不自己实现,使用 OpenZeppelin 库实现
OpenZeppelin 是一个开源的区块链开发工具和智能合约库,旨在帮助开发者安全地构建和部署智能合约。它提供了一系列经过审核和验证的智能合约实现,包括代币标准、访问控制、支付通道等,极大地简化了以太坊和其他区块链平台上的开发工作。
OpenZeppelin 的主要功能和特点
- 安全性: OpenZeppelin 合约经过广泛的审计和验证,确保代码的安全性和可靠性。
- 模块化: 提供可重用的模块化合约,使得开发者可以轻松组合和扩展功能。
- 标准化: 实现了广泛接受的标准,如 ERC20、ERC721 和 ERC1155 等。
- 文档和支持: 提供详尽的文档和活跃的社区支持,帮助开发者快速上手。
使用 OpenZeppelin 的好处
- 节省时间: 提供了常用合约的实现,减少了从零开始编写合约的时间。
- 提高安全性: 经过审核的合约减少了安全漏洞的风险。
- 社区支持: OpenZeppelin 拥有一个庞大且活跃的开发者社区,可以提供支持和帮助。
OpenZeppelin 是区块链开发中不可或缺的工具,提供了安全、可靠和高效的智能合约实现。通过使用 OpenZeppelin,开发者可以更专注于业务逻辑的实现,而不必担心底层合约的安全和稳定性。
参考
- https://etherscan.io/tokens
- https://github.com/OpenZeppelin/openzeppelin-contracts/tree/master/contracts/token/ERC20
- https://www.openzeppelin.com/contracts
- https://ethernaut.openzeppelin.com/
- https://cryptozombies.io/en/course/
- https://eips.ethereum.org/EIPS/eip-20
- https://solidity-by-example.org/app/erc20/
- https://decert.me/tutorial/solidity/solidity-practice/erc20