如何使用IPFS构建ERC-721 NFT

ERC-721标准在以太坊上引起了不可替代令牌(NFT)市场的兴起。ERC-721是创建NFT的标准-一种表达“独特物品”的复杂方式。任何独特的事物都可以是NFT。房子、棒球卡、艺术品等,但它的魅力不在于它的独特性和数字化。魅力在于可证实性。这就是ERC-721标准的亮点所在。 创建ERC-721代币的问题来自于存储基础资产。区块链并不适合存储大量数据。2017年,星际数据库的Jamila Omar估计在以太坊上存储1GB数据的成本将超过400万美元。 因此如果我们知道存储与NFT绑定的资产的成本太高而无法使用区块链,那还有什么选择呢?我们可以使用传统的云存储来存储资产。亚马逊的S3和微软的Azure提供便宜的存储解决方案。但是我们知道传统的云存储存在一个重大缺陷。 可验证性 NFT的重点是数字验证和对可能是实物或数字资产的控制。如果我们无法以类似的方式验证资产的最终所有权,那么我们就无法验证该资产的最终所有权。 解决这两个问题的方法是IPFSIPFS是一个分布式存储网络。它的工作方式与云存储类似。您请求内容并返回该内容。然而,最大的区别在于内容是通过利用全球存储提供商网络来存储的。IPFS利用了一种叫做内容寻址能力的工具。这意味着你不需要向俄亥俄州的数据中心请求一段内容,而是请求内容本身。它可能位于俄亥俄州。可能就在附近。有了内容可寻址性,您不再需要依赖于单个位置来检索内容。这对于全球区块链来说效率要高得多。 IPFS还负责我们的可验证性。由于所有内容都是根据内容本身定义和存储的,因此,如果对某个内容进行篡改或更改,则在尝试验证内容并知道其错误时我们会出现不匹配的情况。让我们通过一个简单的示例使这一点更加清楚: Alice在IPFS上存储一个猫的图片,该图片由一个内容标识符表示。为了简单起见,我们假设标识符是“C”。 Bob下载那只猫的照片,然后在那只可怜的猫身上画了个胡子。当Bob上传图片时,他将不再拥有相同的标识符。因为他已经更改了底层数据(从cat改为mustachioedcat),Bob的标识符可能是“M”。 如果Bob想把他的照片冒充Alice的照片,任何一个细心检查的人都会知道他在撒谎。Alice的标识符与Bob的不匹配,因此,Bob试图冒充Alice的图片是可验证的假的。 我认为您可以在尝试验证NFT等数字资产时开始看到这一点。因此,考虑到这一点,让我们看看如何创建NFT并将关联的资产存储在IPFS上。 对于本教程,您将需要一些注意事项:
  • 文本编辑器
  • 已安装IPFS
  • Ganache-安装了以太坊的本地区块链
  • 安装了Truffle
  • 已安装NodeJS
  • Pinata API密钥
您可以选择任何文本编辑器。我更喜欢Visual Studio Code,但这取决于您。 确定编辑器后,请确保已安装IPFS。 您可以从完整的Truffle套件中的同一位置Truffle和Ganache。 如果您的计算机上还没有Node.js,则还需要下载。 最后,您要确保为其创建NFT的宝贵资产永久存储在IPFS上。这可以通过运行自己的IPFS节点或使用所谓的IPFS固定服务来完成。 编写智能合约 让我们在这里快速免责声明。我不是专业的智能合约开发者。你必须要对智能合约代码进行充分对审计。本文仅供参考,或许会有更好的方法来完成我的内容。 ERC-721代币由智能合约管理。幸运的是,OpenZeppelin的同事让你很容易地写出好的智能合约。我们将使用他们的ERC-721合约来开始。 首先,在您的终端中,创建一个新的项目文件夹。
mkdir mySpecialAsset && cd mySpecialAsset
接下来,我们将使用NPM初始化项目目录。
npm init -y
现在,我们可以利用Truffle初始化我们的智能合约项目。
truffle init
现在,我们需要获得Open Zeppelin智能合约。为此,我们将安装Open Zeppelin的truffle库,如下所示:
npm install @openzeppelin/contracts
我们需要为我们的代币想出一个好名字。我将把我的UniqueAsset称为UniqueAsset,因为我们正在确保nft必须与独特的基础资产相关联。你可以随意称呼你的智能合约。我们希望将合同存放在contracts文件夹中,因此我们将创建如下文件:
touch contracts/UniqueAsset.sol
现在,我们可以打开该文件并开始工作。我们需要指定版本(或与合约兼容的实体版本。我们还需要从Open Zeppelin导入合约框架。我们可以开始实施合约本身。让我们来看一下:
pragma solidity ^0.6.0; import “@openzeppelin/contracts/token/ERC721/ERC721.sol”; import “@openzeppelin/contracts/utils/Counters.sol” contract UniqueAsset is ERC721{ constructor() public ERC721(“UniqueAsset”, “UNA”) {} }
我们需要指定我们使用的Solidity版本。在这种情况下,我使用的是0.6.0。您可以通过编辑truffle-config.js文件来确保Truffle使用正确版本的Solidity编译合约。我正在从Open Zeppelin导入两个合约:ERC721和Counters。计数器只是在发行后帮助我们增加令牌ID。最后,在合约的构造函数中,我们定义了令牌名称和符号。同样,您可以将其设置为任意值。 我们将需要在合约中添加一些逻辑。现在开始吧。 首先,让我们考虑一下我们要在这里做什么。我们要为特定资产发行NFT。我们希望这些资产可验证,就像我们希望所有权可验证一样。因此,我们需要在此处考虑以下几点: 1. 我们希望将NFT与IPFS内容标识符(hash)相关联。2. 我们永远都不想铸造(或创建)与另一个NFT映射到相同IPFS哈希的NFT。 让我们从定义合约中的变量开始,我们将使用这些变量来帮助控制上述两点。在合约代码中的构造函数上方,添加以下内容:
using Counters for Counters.Counter; Counters.Counter private _tokenIds; mapping(string => uint8) hashes; constructor() public ERC721(“UniqueAsset”, “UNA”) {} ….
我们正在使用计数器来帮助我们增加我们铸造的令牌的标识符。我们还将创建一个_tokenIds变量,以跟踪我们已发行的所有令牌。最后对于顶层变量,我们正在为与令牌关联的IPFS哈希创建映射。这将有助于防止发行令牌映射到先前与另一个令牌相关联的哈希。 您的智能合约现在应如下所示:
pragma solidity ^0.6.0; import “@openzeppelin/contracts/token/ERC721/ERC721.sol”; import “@openzeppelin/contracts/utils/Counters.sol”; contract UniqueAsset is ERC721 { using Counters for Counters.Counter; Counters.Counter private _tokenIds; mapping(string => uint8) hashes; constructor() public ERC721(“UniqueAsset”, “UNA”) {} }
我们需要在智能合约中添加一种方法,该方法将允许我们为特定的IPFS哈希值铸造NFT(如果尚未为该哈希值铸造令牌)。我们将在构造函数的下方进行此操作。
function awardItem(address recipient, string memory hash, string memory metadata) public returns (uint256) { require(hashes[hash] != 1); hashes[hash] = 1; _tokenIds.increment(); uint256 newItemId = _tokenIds.current(); _mint(recipient, newItemId); _setTokenURI(newItemId, metadata); return newItemId; }
这里有很多事情,让我们一行一行解读一下。我们的函数有两个参数:一个名为recipient的地址变量、一个名为hash的字符串变量和一个名为metadata的字符串变量。address变量是将接收NFT的人的钱包地址。hash的字符串变量是与我们为其创建NFT的内容相关联的IPFS散列。metadataset的string变量应该引用到资产的JSON元数据的链接。元数据可能包括资产名称、指向引用该资产的图像的链接或任何其他您想要的内容。 然后,在定义我们的功能之后,我们将其public。这只是意味着可以从智能合约外部调用它。我们还将函数的返回值定义为uint256类型。 在此函数内部,如果以前使用散列来创建NFT,我们将使用Solidity的内置 require自动拒绝智能合约调用。您会注意到,我们正在检查hashes映射是否具有匹配的哈希值,该哈希值的整数为1。如果是,则使用该哈希值。 如果哈希没有被使用,我们将通过函数传递的散列添加到哈希映射中,并将其值设置为1)。 最后,我们将增加_tokenIds变量,因为我们将要创建一个新的NFT并铸造令牌,并返回令牌标识符。 这太多信息了,所以让我们快速总结一下,不要依赖代码。我们的合同现在接受一个人的以太坊钱包地址和一个IPFS哈希。它检查以确保哈希与先前生成的NFT不匹配。如果一切正常,那么将针对该IPFS哈希创建一个新的NFT。 好的,我们已经写了智能合约。现在呢? 让我们对其进行编译和部署。记得我曾问过您安装Ganache。我们现在要使用它。通过ganache-cli或使用桌面客户端(我更喜欢桌面客户端)启动Ganache。 如果您查看项目目录,则会看到一个名为migrations的文件夹。我们需要创建一个新的迁移文件。这些文件非常具体,在这种情况下,我们需要它在默认情况下为您创建的现有迁移文件之后运行。为了确保这种情况发生,我们将在迁移文件的开头以2命名。继续并致电您的新迁移2-deploy-contract.js。在该文件中,添加以下内容:
var UniqueAsset = artifacts.require(“UniqueAsset”); module.exports = function(deployer) { deployer.deploy(UniqueAsset); };
用调用智能合约的内容替换对UniqueAsset的引用。 完成并保存后,在终端的项目目录中,运行:
truffle compile
假设您没有遇到任何错误,那么智能合约已经编制完毕,现在可以部署了。只需运行:
truffle migrate
如果出现错误,您可能需要手动设置运行Ganache的端口。桌面客户端使这一点很容易找到。在truffle-config.js文件中,您可以找到network部分并适当设置开发网络端口。 如果一切顺利,你刚刚部署了你的NFT智能合约。这里似乎是一个很好的机会提醒你,我不是一个专家智能合约开发。如果你正在创建智能合约,我肯定会错过一些最佳实践,你应该自己研究一下。 您可以通过在Truffle中针对智能合约编写测试来测试您的智能合约,也可以前往Remix并在其中粘贴您的智能合约并运行测试。如果您进行了测试,则会注意到您可以创建与IPFS哈希关联的NFT,但是如果您尝试为同一哈希创建另一个NFT,则智能合约调用将失败。 现在,我们已经处理了智能合约,我们需要将基础资产添加到IPFS上,并确保在需要创建与之相关的NFT时可用。 将资产添加到IPFS 我们将使用Pinata将我们的资产添加到IPFS,并确保其保持固定状态。我们还将JSON元数据添加到IPFS,以便我们可以将其传递给令牌合约。因此,登录到先前在Pinata上创建的帐户。在右上角,单击帐户下拉菜单,然后选择帐户。在那里,您将能够看到您的API密钥。您可以将鼠标悬停以查看您的API机密。 复制这两个文件,因为我们将在代码中使用它们,以上传我们的资产文件。 单击新建API密钥,然后进行选择。对我来说,我想我只希望该密钥使用一次,并且只希望它可以访问pinFileToIPFS端点,因为这就是我们将资产文件推送到IPFS的方式。 获得API密钥和秘密密钥后,您可以编写一些代码以将资产文件添加到IPFS。如果您在完成所有智能合同后感到疲倦,请不要担心,因为这将非常简单。实际上,如果您想完全跳过代码,Pinata在UI中具有便捷的上传功能。 在代码编辑器中,创建一个名为uploadFile.js的新文件。该目录可以与您创建智能合约的目录相同。在编写代码之前,最好准备好资产文件。只需确保将其保存在您使用的计算机上的某个位置即可。对我来说,我要上传儿子做的一幅画:
如何使用IPFS构建ERC-721 NFT
现在我们已经保存了资产并准备上传,让我们编写代码。我们需要两个依赖关系,以使我们更容易做到这一点。在终端的项目根目录中,运行以下命令:
npm i axios form-data
现在,在uploadFile.js文件中,添加以下内容:
const pinataApiKey = “YOURAPIKEY”; const pinataSecretApiKey = “YOURSECRETKEY”; const axios = require(“axios”); const fs = require(“fs”); const FormData = require(“form-data”); const pinFileToIPFS = async () => { const url = `https://api.pinata.cloud/pinning/pinFileToIPFS`;= let data = new FormData(); data.append(“file”, fs.createReadStream(“./pathtoyourfile.png”)); const res = await axios.post(url, data, { maxContentLength: “Infinity”, headers: { “Content-Type”: `multipart/form-data; boundary=${data._boundary}` pinata_api_key: pinataApiKey, pinata_secret_api_key: pinataSecretApiKey, }, }); console.log(res.data); }; pinFileToIPFS();
成功上传后,您将获得如下结果:
{ IpfsHash: ‘QmfAvnM89JrqvdhLymbU5sXoAukEJygSLk9cJMBPTyrmxo’, PinSize: 2936977, Timestamp: ‘2020-12-03T21:07:13.876Z’ }
该哈希值是您资产的可验证表示。它指向IPFS网络上的资产。如果有人篡改了您的资产并进行了更改,则哈希值将有所不同。通过我们的智能合约创建NFT时应使用该哈希。任何提供公共网关的IPFS主机现在都可以为您显示内容。 我们需要做的最后一件事是创建一个代表我们的资产及其元数据的JSON文件。这使您可能希望列出资产以显示适当的元数据的任何服务都更加容易。让我们创建一个简单的JSON文件,如下所示:
{ “name”:”My Kid’s Art”, “hash”: “QmfAvnM89JrqvdhLymbU5sXoAukEJygSLk9cJMBPTyrmxo”, “by”: “Justin Huner” }
您可以添加所需的任何元数据,但是包含哈希值很重要。这是对实际资产的参考。现在,以与使用Pinata上传资产文件相同的方式上传此文件。当您获取元数据的IPFS哈希值时,请保持方便。创建令牌时需要用到它。 还记得吗,智能合约需要一个Metadata字符串?该字符串将成为元数据的IPFS URL。您将按以下方式构建它:
ipfs://YOUR_METADATA_HASH
综上所述,您将向我们之前创建的智能合约功能传递三个项目:
  • Recipient Address
  • Asset Hash
  • Metadata URL
NFT是我们处理各种商品所有权的方式的一项重要改进。它们易于转让,并简化了创建所有权和证明所有权的过程。但是,缺少的部分是对特定项目所有权的验证。 通过将资产保存到IPFS并将IPFS哈希与资产的NFT相关联,我们可以扩展资产的可验证所有权以验证资产本身的有效性。

该内容来自于互联网公开内容,非区块链原创内容,如若转载,请注明出处:https://htzkw.com/archives/29197

联系我们

aliyinhang@gmail.com