本文将从零开始讲解如何铸造NFT并在OpenSea出售。NFT数藏系统开发,现成源码交流,李铁牛15889726201
首先我们讲讲什么是NFT。NFT是Non-Fungible Token(非同质化代币)的缩写。同质化代币就是BTC、ETH等,即张三手中的一个BTC和李四手中的一个BTC是完全等价的,而NFT则不然,张三手中的一个NFT和李四手中的一个NFT无法等价交换。最早的NFT是由加密猫搞出来的,所有的加密猫都是由同一个合约发行的,但每个猫都不一样,因此,每个猫都有唯一的Token ID,这就是NFT的特点:每个NFT都有一个唯一标识。
不过,需要注意的是,所谓唯一标识,仅仅指在同一个合约中发行的NFT,他们的Token ID都是唯一的,不同的合约发行的NFT,很可能有相同的Token ID。因此,一个NFT真正的唯一标识,实际上是合约地址+Token ID。
在OpenSea中,一个Collection,例如CryptoPunks,就是一个合约发出的所有NFT。所以,要发行一个Collection,首先要创建一个合约,然后,用这个合约发行的所有NFT就自动被归集到这个Collection中。
NFT有两个标准:EIP-721和EIP-1155。721标准比较简单,它只需要保证一个NFT对应一个唯一的Token ID就行,因为一个Token ID对应的NFT只有一个,而1155就要宽松一点,一个NFT可以有多个,比如一个头像有10个,那最多允许10个人持有。如果每个NFT只发1个,那就和721没啥区别了。
所以我们只需要支持1155,就相当于兼容了721。1155的NFT接口主要有以下几个:
根据一个Token ID返回Metadata的URL:uri(uint256 id)
查询一个地址拥有的Token ID数量:balanceOf(address account, uint256 id)
授权或取消授权一个地址有权转移NFT:setApprovalForAll(address operator, bool approved)
转移一个NFT:safeTransferFrom(address from, address to, uint256 id, uint256 amount, bytes calldata data)
EIP-1155定义的接口和实现都可以在OpenZeppelin上找到,我们只需要在ERC1155的基础上修改即可。ERC1155的核心代码其实就是一个映射,记录Token ID到持有地址、再到持有数量:
contract ERC1155 { // Mapping from token ID to account balances mapping(uint256 => mapping(address => uint256)) private _balances; }
我们做的主要修改是增加一个Token ID到URL的映射。因为我们准备将NFT的图片和Metadata数据都放到IPFS上,所以增加一个Token ID到IPFS文件哈希的映射:
第二个修改是增加一个mint()方法来铸造NFT:
最后一步是在isApprovedForAll()中判断下当前转移操作的发起者是不是OpenSea的代理合约:
这么做的目的是将来在OpenSea售卖的时候,不需要授权操作,节省了gas费,缺点是无条件信任了OpenSea的代理合约,降低了一点安全性。
NFT铸造流程
理解NFT的铸造流程是非常重要的。首先,一个NFT关联了一个特定的资源,如图片、视频、3D模型、VR等。假定我们的NFT就是一个图片,铸造NFT的第一步是将图片上传并获得一个固定的URL。这里我们选择IPFS,上传成功后返回的URL类似:
https://ipfs.infura.io/ipfs/QmaCR37BEGv6aZzzfJ1ShT8tu52UWosVgN9ookYY94FVVt?filename=file.png
第二步是准备NFT的Metadata,也就是NFT的描述信息。标准的Metadata就是一个JSON文件,内容如下:
attributes就是NFT的属性,有多少个就往里填多少个。JSON文件也需要一个URL,可以用服务器的API返回,也可以直接上传到IPFS拿到一个URL,这个JSON的URL就是NFT的Metadata的URL,也是合约方法uri(uint256 id)返回的URL。
最后一步,我们调用mint()方法并传入NFT的Metadata的IPFS哈希,就完成了一个NFT的铸造!
铸造后默认的持有人是铸造者本人。如果切换到OpenSea并以铸造者身份登录,就可以看到我们刚铸造出的NFT:
那么问题来了:OpenSea是如何知道我们铸造的NFT并且获得了NFT的图片以及相关信息?
因为我们在铸造的时候,mint()方法写入了一条NFT转移日志,该日志记录了NFT的Token ID、数量和所有者,OpenSea读取链上的日志就可以知道该地址拥有了新铸造的NFT以及NFT的ID和数量。
紧接着,OpenSea通过调用合约方法uri(uint256 id)可以获得Metadata的URL,读取该JSON后,通过JSON文件内的”image”:”https://…”可以获取到NFT对应的图片URL,这样,根据一个合约地址和Token ID,可以获得一个NFT的所有信息。
最后,我们还需要编写一个页面,能把上传图片、设置Metadata、上传Metadata、调用合约mint()方法一键完成。可以参考网页https://michaelliao.github.io/simple-nft/:
有的同学已经看出来了,一个NFT除了Token ID和数量写在合约里不能变以外,返回的URL虽然链接是固定的,但是完全可以控制该URL以便返回修改后的Metadata,所以Metadata的内容是完全可以修改的,它对应的图片也是完全可以修改的,因此,所谓NFT不可修改,仅仅指Token ID和数量不能修改,NFT背后对应的元数据和资源文件都是可修改的,会不会修改完全看开发者的人品,并且元数据的URL也是有可能失效的。
最后我们总结一下发行NFT的5个步骤:
1.编写并部署一个1155合约;
2.上传资源文件(例如图片);
3.上传Metadata文件;
4.写入合约铸造;
5.在OpenSea售卖。
NFT数藏系统开发,NFT数藏系统现成源码交流,李铁牛15889726201