# ERC721

By [un.Block](https://paragraph.com/@un-block) · 2021-10-09

---

NFT 背后的技术是 ERC721 或 ERC1155， 今天我们就来学习一下 ERC721 的开发，说不定过两周 un.Block 就有自己的 NFT 了

### **NFT 的组成**

首先，在 ERC721 的合约中，每个 NFT 都有以下内容

*   `name`: 代币名字
    
*   `symbol`: 代币符号
    
*   `tokenID`: 代币编号
    
*   `URI`**： NFT元数据**
    

其中，元数据是 NFT 最重要的部分，它直接决定了 NFT 里面存放的内容。对于一些图片类的 NFT ，元数据通常都会存放图片的链接字符串，这个链接可能是中心化网站的链接（就像我们日常用的图床链接一样），或者是 ipfs 链接。

实际上，元数据可以存放的不只有字符串，以下是在 EIP-721 中给出的元数据示例：

关于 NFT 元数据的存储问题，在之前的周报 [_#12_](https://link.zhihu.com/?target=https%3A//unblock256.substack.com/p/unblock-2021-12nft-)[_#13_](https://link.zhihu.com/?target=https%3A//unblock256.substack.com/p/unblock-2021-13uniswap-v3filecoin) 已经解释过了，大家有兴趣可以自行阅读。

**漫游 ERC721**

EIP-721 给了关于 ERC721 的 3 个接口，分别是：

*   `IERC721`: 核心 ERC721
    
*   `IERC721Metadata`: ERC721 元数据
    
*   `IERC721Enumerable`: 关于 ERC721 的供应量、序号之类的数字接口
    

其中，**IERC721** 是唯一必须实现的接口，但这个接口过于简单，几乎没有项目会只实现一个 IERC721 就发布。

因此，我们将和大家分享多一些关于 ERC721 实用接口。

除了上述的 3 个接口之外，还有以下功能可以让 ERC721 锦上添花：

*   `ERC721Pausable`: 暂停 ERC721 代币交易
    
*   `ERC721Burnable`: 摧毁代币！
    
*   `AccessControl`: 合约权限管理
    

OpenZepplin 给出了一个功能较为完善的 ERC721 合约范例 —— [**_ERC721PresetMinterPauserAutoId_**](https://link.zhihu.com/?target=https%3A//docs.openzeppelin.com/contracts/3.x/api/presets%23ERC721PresetMinterPauserAutoId) 这个范例能在 ERC721 的基础上实现以下功能：

*   允许用户摧毁掉自己的代币
    
*   一个铸造者 (minter) 角色来负责铸造代币
    
*   一个交易管理员角色 (pauser)，有权暂停代币转账
    
*   自动生成代币编号(tokenID) 和 元数据 (URI)
    

**ERC721: 元数据与铸币**

ERC721 在某些功能，如查询余额、授权、转账，与 ERC20 如出一辙（我们在 #9 跟大家介绍过 ERC20），值得深入了解的就是 ERC721 的元数据与铸币过程

1⃣️元数据以 `mapping` 的形式存储

![](https://storage.googleapis.com/papyrus_images/37b18e463267d40fa506846aaffc28994f6417ea0f5d729139c11051e7a20685.jpg)

1⃣️ 通过 `_setTokenURI` 函数，我们可以设置 URI，这里需要传入 tokenID 和 URI元数据

![](https://storage.googleapis.com/papyrus_images/d05f7756728557bd986ee1826566ef13735edf565519112bef6775b3d3bbb24c.jpg)

3⃣️ ERC721 的 `_mint` 函数和 ERC20 很相似，本质就是将代币分发给用户，由于 tokenID 代表了 NFT 代币，因此调用 mint 函数的时候只需要指定用户和 tokenID 即可

![](https://storage.googleapis.com/papyrus_images/c79dd21ce1e1ae19046e9bc15c9874d3f3a8dd6f27792a149ca41820f2a0697d.jpg)

值得一提的是，OpenZepplin 并不推荐我们直接使用 `_mint`，而是推荐使用 `_safeMint` 来铸造代币

`_safeMint` 会在铸造前进行检查，要求如下：

*   `tokenID` 需要不存在，可以理解为这个 tokenID 对应的 NFT 还没有被铸造
    
*   收款地址需要有接受 ERC721 代币的能力，这个检查主要是针对为了合约接收代币
    

**相关阅读：**

*   [_How to create and deploy an ERC-721 (NFT)_](https://link.zhihu.com/?target=https%3A//www.quicknode.com/guides/solidity/how-to-create-and-deploy-an-erc-721-nft)
    
*   [_ERC-721 NON-FUNGIBLE TOKEN STANDARD_](https://link.zhihu.com/?target=https%3A//ethereum.org/en/developers/docs/standards/tokens/erc-721/)

---

*Originally published on [un.Block](https://paragraph.com/@un-block/erc721)*
