ERC20 标准实现
1. 系统概述
ERC20 标准实现是一个基于 Solidity 实现的标准代币合约,完全符合 ERC20 标准接口规范。该实现包含了代币的基本功能和扩展功能,并添加了必要的安全机制。
1.1 主要特点
- 标准兼容:完全符合 ERC20 标准
- 基础功能:转账、授权、查询等基本操作
- 扩展功能:增加/减少授权等扩展操作
- 事件追踪:完整的事件日志记录
- 安全检查:完善的安全性验证
- 精确计算:支持小数位配置
2. 合约实现
solidity
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;
import "@openzeppelin/contracts/utils/Context.sol";
import "@openzeppelin/contracts/utils/math/SafeMath.sol";
/**
* @title ERC20 Token
* @dev ERC20 标准代币实现
*/
contract ERC20 is Context {
using SafeMath for uint256;
// 状态变量
string private _name; // 代币名称
string private _symbol; // 代币符号
uint8 private _decimals; // 小数位数
uint256 private _totalSupply; // 总供应量
mapping(address => uint256) private _balances; // 账户余额
mapping(address => mapping(address => uint256)) private _allowances; // 授权额度
// 事件
event Transfer(address indexed from, address indexed to, uint256 value);
event Approval(address indexed owner, address indexed spender, uint256 value);
/**
* @dev 构造函数
*/
constructor(
string memory name_,
string memory symbol_,
uint8 decimals_,
uint256 totalSupply_
) {
require(bytes(name_).length > 0, "ERC20: name is empty");
require(bytes(symbol_).length > 0, "ERC20: symbol is empty");
_name = name_;
_symbol = symbol_;
_decimals = decimals_;
// 初始化总供应量
_mint(_msgSender(), totalSupply_);
}
/**
* @dev 获取代币名称
*/
function name() public view returns (string memory) {
return _name;
}
/**
* @dev 获取代币符号
*/
function symbol() public view returns (string memory) {
return _symbol;
}
/**
* @dev 获取小数位数
*/
function decimals() public view returns (uint8) {
return _decimals;
}
/**
* @dev 获取总供应量
*/
function totalSupply() public view returns (uint256) {
return _totalSupply;
}
/**
* @dev 获取账户余额
*/
function balanceOf(address account) public view returns (uint256) {
return _balances[account];
}
/**
* @dev 获取授权额度
*/
function allowance(address owner, address spender) public view returns (uint256) {
return _allowances[owner][spender];
}
/**
* @dev 转账
*/
function transfer(address to, uint256 amount) public returns (bool) {
address owner = _msgSender();
_transfer(owner, to, amount);
return true;
}
/**
* @dev 授权
*/
function approve(address spender, uint256 amount) public returns (bool) {
address owner = _msgSender();
_approve(owner, spender, amount);
return true;
}
/**
* @dev 授权转账
*/
function transferFrom(
address from,
address to,
uint256 amount
) public returns (bool) {
address spender = _msgSender();
_spendAllowance(from, spender, amount);
_transfer(from, to, amount);
return true;
}
/**
* @dev 增加授权额度
*/
function increaseAllowance(address spender, uint256 addedValue) public returns (bool) {
address owner = _msgSender();
_approve(owner, spender, _allowances[owner][spender].add(addedValue));
return true;
}
/**
* @dev 减少授权额度
*/
function decreaseAllowance(address spender, uint256 subtractedValue) public returns (bool) {
address owner = _msgSender();
uint256 currentAllowance = _allowances[owner][spender];
require(currentAllowance >= subtractedValue, "ERC20: decreased allowance below zero");
unchecked {
_approve(owner, spender, currentAllowance - subtractedValue);
}
return true;
}
/**
* @dev 内部转账函数
*/
function _transfer(
address from,
address to,
uint256 amount
) internal virtual {
require(from != address(0), "ERC20: transfer from the zero address");
require(to != address(0), "ERC20: transfer to the zero address");
uint256 fromBalance = _balances[from];
require(fromBalance >= amount, "ERC20: transfer amount exceeds balance");
unchecked {
_balances[from] = fromBalance - amount;
_balances[to] += amount;
}
emit Transfer(from, to, amount);
}
/**
* @dev 内部铸币函数
*/
function _mint(address account, uint256 amount) internal virtual {
require(account != address(0), "ERC20: mint to the zero address");
_totalSupply = _totalSupply.add(amount);
unchecked {
_balances[account] += amount;
}
emit Transfer(address(0), account, amount);
}
/**
* @dev 内部销毁函数
*/
function _burn(address account, uint256 amount) internal virtual {
require(account != address(0), "ERC20: burn from the zero address");
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);
}
/**
* @dev 内部授权函数
*/
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");
_allowances[owner][spender] = amount;
emit Approval(owner, spender, amount);
}
/**
* @dev 内部扣减授权额度函数
*/
function _spendAllowance(
address owner,
address spender,
uint256 amount
) internal virtual {
uint256 currentAllowance = allowance(owner, spender);
if (currentAllowance != type(uint256).max) {
require(currentAllowance >= amount, "ERC20: insufficient allowance");
unchecked {
_approve(owner, spender, currentAllowance - amount);
}
}
}
}
3. 功能说明
3.1 基础功能
- 代币信息查询:名称、符号、小数位、总供应量
- 账户余额查询:查询指定账户的代币余额
- 授权额度查询:查询授权给指定账户的代币额度
3.2 交易功能
- 转账:直接转账给其他账户
- 授权:授权其他账户使用代币
- 授权转账:使用授权额度转账
3.3 扩展功能
- 增加授权:增加对指定账户的授权额度
- 减少授权:减少对指定账户的授权额度
- 铸币和销毁:内部函数支持代币的铸造和销毁
4. 安全机制
4.1 地址验证
- 零地址检查:禁止与零地址进行交互
- 地址有效性验证:确保地址格式正确
4.2 数值检查
- 余额充足性检查:确保转账和销毁操作有足够余额
- 授权额度验证:确保授权转账在授权额度内
- 数值溢出保护:使用 SafeMath 防止数值溢出
4.3 状态管理
- 原子性操作:确保状态更新的原子性
- 事件记录:记录所有重要操作的事件
- 授权管理:安全的授权额度管理
5. 使用示例
5.1 部署代币
javascript
const name = "My Token";
const symbol = "MTK";
const decimals = 18;
const totalSupply = ethers.utils.parseEther("1000000");
const token = await ERC20.deploy(name, symbol, decimals, totalSupply);
await token.deployed();
5.2 转账代币
javascript
const to = "0x1234...";
const amount = ethers.utils.parseEther("100");
await token.transfer(to, amount);
5.3 授权和授权转账
javascript
// 授权
const spender = "0x5678...";
const amount = ethers.utils.parseEther("1000");
await token.approve(spender, amount);
// 授权转账
const from = "0x1234...";
const to = "0x9012...";
await token.transferFrom(from, to, amount);
6. 总结
该 ERC20 标准实现提供了一个完整的代币合约,包括:
- 完全符合 ERC20 标准的接口实现
- 安全的代币转账和授权机制
- 完善的数值检查和地址验证
- 灵活的授权管理功能
- 详细的事件记录系统
通过严格遵循 ERC20 标准并添加必要的安全检查,该实现为开发者提供了一个可靠、安全的代币合约基础。
常见问题解答(FAQ)
Q: 什么是 ERC20 标准?
A: ERC20 是以太坊上最广泛使用的代币标准之一,它定义了一组接口规范,使得代币可以在以太坊网络上统一地进行转账、授权等操作。
Q: 为什么需要授权(Approve)机制?
A: 授权机制允许代币持有者授权其他地址(如智能合约)代表自己使用一定数量的代币,这对于 DEX、借贷等 DeFi 应用是必需的。
Q: 代币的小数位(Decimals)是什么意思?
A: 小数位定义了代币的最小可分割单位。例如,decimals = 18 意味着 1 个代币可以分割成 10^18 个最小单位。
Q: 如何防止代币合约被攻击?
A: 主要通过以下方式:
- 使用 SafeMath 防止数值溢出
- 严格的地址检查
- 完善的权限控制
- 全面的安全测试
Q: 如何处理误转入合约的代币?
A: 建议实现额外的恢复机制,但标准的 ERC20 实现并不包含这个功能。如果代币被误转到合约地址,且合约没有相应的处理函数,这些代币可能会永久丢失。