# NFT & ERC721 & ERC1155(考虑一下)
## Outline
- [x] NFT Cointains what?
- [ ] ERC721 & ERC1155 diffrence?
- [x] NFT Data Storage(Link to ever posts)
- [x] :flashlight: Inside ERC721
- [ ] :thinking_face: THINK: NFT?
## Content
### NFT 的组成
首先我们来看看一个 NFT 里面究竟有什么东西:
找个NFT,截图+ 数据,
我们可以看到,一个 NFT 是由以下三部分组成:
- name 名字
- symbol 代币符号
- URI NFT元数据
其中,元数据是 NFT 最重要的部分,它决定了 NFT 里面纠结有什么。对于一些图片类的 NFT 来说,元数据通常都会存放图片的链接,这个链接可能是中心化网站的链接,或者是 ipfs 链接
如
https://ipfs.io/ipfs/bafkreiemnftbduxffrv62icdtwyr6fdylgdxteapjl76rhtoikh6x6bavm
其实大部分 NFT 都只放了一个链接....没那么多东西,下面是官方的元数据示范,写的是 JSON,大家可以看看
(官方的截图
关于 NFT 元数据的存储问题,在之前的周报 #几 #几 已经解释过了,大家有兴趣可以自行阅读。至于最近热门的 NFT 是怎么存储的,可以看这篇文章 https://www.chainnews.com/articles/363603486355.htm?utm_source=telegra
CryptoPunks、加密猫、小企鹅都没有在链上存储元数据
### 在 ERC721 畅游
EIP-721 给了关于 ERC721 的 3 个接口,分别是:
- IERC721: 核心 ERC721
- IERC721Metadata: ERC721 元数据
- IERC721Enumerable: 关于 ERC721 的供应量、序号之类的数字接口
其中,IERC721 是唯一必须要实现的借口,但这是在是太简单了,与主流 NFT 项目的标准还有一定的距离。因此,我们将和大家分享多一些关于 ERC721 能用到的功能和接口。
除了上述 3 个接口之外,还有以下功能是可以添加上去的:
- ERC721Pausable:用于管理 ERC721 的代币转账
- ERC721Burnable:摧毁代币!
- AccessControl:合约权限管理
我们以 OpenZepplin 的 ERC721PresetMinterPauserAutoId 范例合约为例来看,这个范例可以实现以下功能:
- 允许用户摧毁掉自己的代币
- 一个铸造者(minter)角色来负责铸造代币
- 一个交易管理员角色(pauser),有权暂停代币转账
- 自动生成 tokenID 和 元数据
### ERC721
我们主要关注的是元数据的写入以及代币的铸造过程
首先,元数据以 mapping 的形式存储
```solidity=
// Optional mapping for token URIs
mapping (uint256 => string) private _tokenURIs;
```
通过 _setTokenURI 函数,我们可以设置 URI,这里需要传入 tokenID 和 URI 元数据
```solidity=
function _setTokenURI(uint256 tokenId, string memory _tokenURI) internal virtual {
require(_exists(tokenId), "ERC721Metadata: URI set of nonexistent token");
_tokenURIs[tokenId] = _tokenURI;
}
```
ERC721 对 _mint 函数和 ERC20 很相似,本质就是将代币分发给用户,由于 TokenID 代表了 NFT 代币,因此调用 mint 函数的时候只需要指定用户和 tokenID 即可
```solidity=
function _mint(address to, uint256 tokenId) internal virtual {
require(to != address(0), "ERC721: mint to the zero address");
require(!_exists(tokenId), "ERC721: token already minted");
_beforeTokenTransfer(address(0), to, tokenId);
_holderTokens[to].add(tokenId);
_tokenOwners.set(tokenId, to);
emit Transfer(address(0), to, tokenId);
}
```
值得一提的是,OpenZepplin 并不推荐我们直接使用 _mint,而是推荐使用 _safeMint
```solidity=
/**
* @dev Safely mints `tokenId` and transfers it to `to`.
*
* Requirements:
d*
* - `tokenId` must not exist.
* - If `to` refers to a smart contract, it must implement {IERC721Receiver-onERC721Received}, which is called upon a safe transfer.
*
* Emits a {Transfer} event.
*/
function _safeMint(address to, uint256 tokenId) internal virtual {
_safeMint(to, tokenId, "");
}
/**
* @dev Same as {xref-ERC721-_safeMint-address-uint256-}[`_safeMint`], with an additional `data` parameter which is
* forwarded in {IERC721Receiver-onERC721Received} to contract recipients.
*/
function _safeMint(address to, uint256 tokenId, bytes memory _data) internal virtual {
_mint(to, tokenId);
require(_checkOnERC721Received(address(0), to, tokenId, _data), "ERC721: transfer to non ERC721Receiver implementer");
}
```
_safeMint 会在 mint 之前进行检查,要求如下:
- tokenID 不存在,意思就是这个 tokenID 对应的 NFT 还没有被 mint
- 收款地址需要有接受 ERC721 代币的能力,这个检查主要是为了合约收款而设置的
### 额外功能
### Pausable
Pausable 合约在 OpenZepplin 的 utils 工具库中。它的原理比较简单,就是控制一个叫 _paused 的 bool 类型变量,在调用交易函数前可以对这个变量进行检查,假如 _paused 为 True,就无法进行交易。
修改 _paused 的值会触发对应的事件。
https://docs.openzeppelin.com/contracts/3.x/api/utils#Pausable-paused--
### ERC721Burnable
摧毁代币的真的很简单 🤣,直接调用 `burn(uint256 tokenId)`,传入 tokenID 即可。
https://github.com/OpenZeppelin/openzeppelin-contracts/blob/v3.4.0/contracts/token/ERC721/ERC721.sol
----
## Draft
### NFT Cointains what?
-> **ERC721Metadata**
Functions:
- name()
- symbol()
- tokenURI(tokenId)
URI 数据是什么
https://en.wikipedia.org/wiki/Uniform_Resource_Identifier
A Uniform Resource Identifier (URI) is a unique sequence of characters that identifies a logical or physical resource used by web technologies.
URIs may be used to identify anything, including real-world objects, such as people and places, concepts, or information resources such as web pages and books.
## Ref
### Codes~~~
EIP721: https://eips.ethereum.org/EIPS/eip-721
Ethereum Org: https://ethereum.org/en/developers/docs/standards/tokens/erc-721/
OPZL: https://docs.openzeppelin.com/contracts/3.x/api/presets#ERC721PresetMinterPauserAutoId