关键词:interface、event、hook、可选扩展、继承结构、ERC165、模块化设计
📚 作者:Henry 🧱 系列:《ERC 系列标准全景图解》 · 第 2 篇 👨💻 受众:Web3 前端工程师 / 区块链开发者 / Web3入门者 👉 系列持续更新中,建议收藏专栏或关注作者
许多开发者使用 ERC-20、ERC-721 时,都是照抄接口或者用库。然而在合约开发中,只有真正理解 ERC 标准的结构与组成,才能做到定制、安全、可扩展的开发。
想要掌握如何拆解一个 ERC 标准文档?本篇文章就是为此而写。
以 ERC-721 原文为例,主要结构如下:
模块 | 含义 |
---|---|
Motivation | 标准提出的背景与目的 |
Specification | Solidity 接口定义(interface + event) |
Rationale | 各字段 / 方法的设计动机与行为约束说明 |
Backwards Compatibility | 与其他标准的兼容性处理 |
Test Cases | 推荐测试场景 / 方法 |
Reference Implementation | 官方实现参考 |
✅ 工程落地中,最重要的阅读部分是:Specification + Rationale
ERC 标准通过 Solidity interface 来定义合约必须暴露的接口。
interface IERC20 {
function totalSupply() external view returns (uint256);
function balanceOf(address account) external view returns (uint256);
function transfer(address to, uint256 amount) external returns (bool);
function approve(address spender, uint256 amount) external returns (bool);
function transferFrom(address from, address to, uint256 amount) external returns (bool);
}
每个函数定义都具有行为约束,比如:
transfer
应触发 Transfer
事件approve
不应更改已有授权前提下直接覆盖类别 | 示例 |
---|---|
函数(interface) | transfer , approve , ownerOf |
事件(event) | Transfer , Approval , ApprovalForAll |
接收钩子(hook) | onERC721Received , onERC1155Received |
元信息(metadata) | name , symbol , tokenURI |
可选接口(optional) | 如 ERC721Enumerable , ERC721Burnable |
接口检测(ERC165) | supportsInterface(bytes4) |
ERC 标准经常只定义最小接口,而实际使用中需要扩展,如:
totalSupply()
和按索引查询 tokenpermit()
支持签名授权这些扩展通常通过模块继承来实现:
contract MyNFT is ERC721, ERC721Enumerable, ERC721Burnable {}
🧠 OpenZeppelin 的模块划分,是标准工程化最好的模板
以太坊提供 ERC165
标准,用于识别某个合约是否实现了某个接口:
function supportsInterface(bytes4 interfaceId) external view returns (bool);
接口 ID 通常使用 XOR 计算,例如 ERC721 的 ID 为 0x80ac58cd
📌 示例:钱包 / DApp 可调用该函数自动判断合约是否是 NFT、1155、ERC20...
以下是推荐的模块结构辨认法(以 ERC721 为例):
ERC721Core.sol → 标准基础功能
└─ ERC721Metadata.sol → 可选元信息扩展
└─ ERC721Enumerable.sol → 可选索引支持扩展
└─ ERC721Burnable.sol → 可选销毁扩展
└─ ERC721URIStorage.sol → 可选链上 URI 存储
推荐查看:
IERC721
接口定义决定了前端调用方式。以 approve(...)
为例:
const contract = new ethers.Contract(tokenAddress, ERC20_ABI, signer)
await contract.approve(spenderAddress, amount)
如果接口定义中未返回 boolean(如 USDT),这段代码就可能报错。
✅ 解决方案:
try {}
包裹调用SafeERC20
自动处理异常面试官可能会问:
Q:ERC-721 为什么使用 safeTransferFrom 而不是 transfer?
推荐回答结构:
- transfer 是直接调用,不会验证接收方合约是否能处理 NFT
- safeTransferFrom 会调用 onERC721Received,防止误转
- 避免 NFT 被锁死在不支持接收的合约中
- ERC 标准通过这个 hook 实现接收方责任机制
⚠️ 切记面试不要只说“这是标准规定”,要讲清“设计原因 + 使用后果”
如果觉得我的文章对您有用,请随意打赏。你的支持将鼓励我继续创作!