华企号 后端开发 NFT数藏系统之铸造原理和技术开发细节

NFT数藏系统之铸造原理和技术开发细节

本文将从零开始讲解如何铸造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文件哈希的映射:

contract ERC1155 {
mapping(uint256 => string) private _metadataHashes;
string private _uriPrefix = “https://ipfs.infura.io/ipfs/”;

// 返回”https://ipfs.infura.io/ipfs/QmasWH…re2Ych?filename=metadata.json”
// 如果使用服务器API返回则可以固定uri为”https://api.example.com/metadata/{id}”
function uri(uint256 id) public view returns (string memory) {
return _concat(_uriPrefix, _metadataHashes[id], “?filename=metadata.json”);
}
}

第二个修改是增加一个mint()方法来铸造NFT:

function mint(uint256 amount, string memory metadataHash) public returns (uint256) {
// 如果只允许合约部署者铸造,加上判断:
// require(msg.sender == owner, “Not contract owner”);
nextTokenId++;
uint256 tokenId = nextTokenId;
_metadataHashes[tokenId] = metadataHash;
_mint(msg.sender, tokenId, amount, “”);
return tokenId;
}

最后一步是在isApprovedForAll()中判断下当前转移操作的发起者是不是OpenSea的代理合约:

function isApprovedForAll(address account, address operator) public view returns (bool) {
// Whitelist OpenSea proxy contract for easy trading.
ProxyRegistry proxyRegistry = ProxyRegistry(proxyRegistryAddress);
if (address(proxyRegistry.proxies(account)) == operator) {
return true;
}
return _operatorApprovals[account][operator];
}

这么做的目的是将来在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文件,内容如下:

{
“name”: “EIP-1155 based NFT”,
“description”: “Public Mintable EIP-1155 based NFT”,
“external_url”: “https://michaelliao.github.io/simple-nft/”,
“image”: “https://ipfs.infura.io/ipfs/QmaCR37BEGv6aZzzfJ1ShT8tu52UWosVgN9ookYY94FVVt?filename=file.png”,
“attributes”: [
{
“trait_type”: “Type”,
“value”: “EIP-1155”
},
{
“trait_type”: “Author”,
“value”: “Crypto Michael”
}
]
}

attributes就是NFT的属性,有多少个就往里填多少个。JSON文件也需要一个URL,可以用服务器的API返回,也可以直接上传到IPFS拿到一个URL,这个JSON的URL就是NFT的Metadata的URL,也是合约方法uri(uint256 id)返回的URL。

最后一步,我们调用mint()方法并传入NFT的Metadata的IPFS哈希,就完成了一个NFT的铸造!

铸造后默认的持有人是铸造者本人。如果切换到OpenSea并以铸造者身份登录,就可以看到我们刚铸造出的NFT:

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数藏系统之铸造原理和技术开发细节插图1

有的同学已经看出来了,一个NFT除了Token ID和数量写在合约里不能变以外,返回的URL虽然链接是固定的,但是完全可以控制该URL以便返回修改后的Metadata,所以Metadata的内容是完全可以修改的,它对应的图片也是完全可以修改的,因此,所谓NFT不可修改,仅仅指Token ID和数量不能修改,NFT背后对应的元数据和资源文件都是可修改的,会不会修改完全看开发者的人品,并且元数据的URL也是有可能失效的。

最后我们总结一下发行NFT的5个步骤:

1.编写并部署一个1155合约;
2.上传资源文件(例如图片);
3.上传Metadata文件;
4.写入合约铸造;
5.在OpenSea售卖。

作者: 李铁牛程序员

李铁牛,一直致力于企业客户软件定制开发,计算机专业毕业后,一直从事于互联网产品开发到现在。微信技术交流:tieniu6636
上一篇
下一篇

发表回复

联系我们

联系我们

028-84868647

在线咨询: QQ交谈

邮箱: tech@68v8.com

工作时间:周一至周五,9:00-17:30,节假日休息

关注微信
微信扫一扫关注我们

微信扫一扫关注我们

关注微博
返回顶部