ERC20
EIP&ERC: https://eips.ethereum.org/EIPS/eip-20 官方文档:https://docs.openzeppelin.com/contracts/5.x/api/token/ERC20#core 在token/ERC20路径下首先是ERC20.sol和IERC20.sol这是基本的,然后在文件extensions下,有一些拓展。在utils下有一些高度抽象后的,比较通用的工具
tips
如果一个应用场景用不到name,symbol,decimals,那么就引用IERC20即可,反之就要引用IERC20Metadata了
interface IERC20
定义了基本的转账授权方法。
import "@openzeppelin/contracts/token/ERC20/IERC20.sol";
ERC20
完整的ERC20实现,要想实现一个ERC20代币,直接继承这个库就行了
import "@openzeppelin/contracts/token/ERC20/ERC20.sol";
使用实例
//SPDX-License-Identifier: UNLICENSED
pragma solidity ^0.8.0;
import "@openzeppelin/contracts/token/ERC20/ERC20.sol";
contract C2NToken is ERC20 {
uint8 private _decimals;
constructor (string memory name_, string memory symbol_, uint256 totalSupply_, uint8 decimals_) ERC20( name_, symbol_) {
_decimals=decimals_;
_mint(_msgSender(), totalSupply_);
}
function decimals() public view override returns (uint8){
return _decimals;
}
function burn(uint amount) external {
_burn(_msgSender(), amount);
}
function mint(uint amount) external {
_mint(_msgSender(), amount);
}
}
SafeERC20
对于转账提供了安全的方法,ERC20 标准中,不同代币实现的行为不一致: 有些代币失败时返回 false(如某些旧实现) 有些代币失败时直接 revert(如 OpenZeppelin 的实现)SafeERC20失败时统一为revert
// 须同时导入两个模块
// 标准导入模板
import "@openzeppelin/contracts/token/ERC20/IERC20.sol";
import "@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol";
contract MyContract {
using SafeERC20 for IERC20; // 启用安全方法
IERC20 public token;
function transferTokens(address to, uint256 amount) external {
token.safeTransfer(to, amount); // ✅ 总是使用 safeTransfer
}
}
最佳实践总结
1、需要转账/授权操作:使用 SafeERC20
2、只需要查询余额:IERC20.balanceOf() 即可
3、需要元数据(name/symbol/decimals): 导入 IERC20Metadata
4、只需要基本接口: 导入 IERC20
interface IERC20Metadata
定义了三个基础信息方法,name,symbol,decimals,另外就是继承IERC20的方法与事件了
import "@openzeppelin/contracts/token/ERC20/extensions/IERC20Metadata.sol";
继承关系
interface IERC20Metadata is IERC20
interfaces路径下的 IERC20
import "@openzeppelin/contracts/interfaces/IERC20Metadata.sol"; 其中也是导入的也是token下的IERC20Metadata
import "@openzeppelin/contracts/token/ERC20/extensions/IERC20Metadata.sol";