本文将解释如何从头开始铸造NFT并在opensea中销售。
首先,让我们谈谈NFT是什么。NFT是非同质令牌的缩写。同质令牌是BTC、ETH等,即张三手中的BTC和李四手中的BTC是完全等效的,而NFT不是。不能等价地交换张三手中的NFT和李四手中的NFT。最早的NFT是由加密猫制作的。所有加密猫均由同一份合同签发,但每种猫都不同。因此,每个cat都有一个唯一的令牌ID。这是NFT的特征:每个NFT都有一个唯一标识符
然而,应该注意的是,所谓的唯一标识符仅指在同一合同中发布的NFT,它们的令牌ID都是唯一的。在不同合同中发布的NFT可能具有相同的令牌ID。因此,NFT的真正唯一标识符实际上是合同地址+令牌ID
在opensea中,集合(如Cryptopunk)都是由合同发送的NFT。因此,要发布集合,首先创建一个合同,然后所有与此合同一起发布的NFT将自动收集到此集合
NFT有两个标准:eip-721和eip-1155。721标准相对简单。它只需要确保NFT对应于唯一的令牌ID,因为令牌ID只对应于一个NFT,而1155稍微宽松一些。一个NFT可以有多个,例如,有10个化身,最多可以由10个人持有。如果每个NFT只发送一个,那么它与721
没有什么不同,因此我们只需要支持1155,这相当于与721兼容。1155的NFT接口主要包括以下内容:
根据令牌ID返回元数据的URL:URI(uint256 ID)
查询地址拥有的令牌ID数:balanceof(address account,uint256 ID)
授权或取消授权地址传输NFT:setapprovalforall(address operator,boot approved)
传输NFT:safetransferfrom(address from,address to,uint256 ID,uint256 amount, bytes calldata data)可以在openzeppelin上找到369eip-1155定义的接口和实现。我们只需要在erc1155的基础上进行修改。erc1155的核心代码实际上是一个映射,将令牌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:
那么问题来了: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售卖。
原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。
如有侵权,请联系 cloudcommunity@tencent.com 删除。
原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。
如有侵权,请联系 cloudcommunity@tencent.com 删除。