如何使用IPFS构建ERC-721 NFT

2020-12-09 16:02:48

IPFS是解决构建ERC-721 NFT的唯一途径

  该ERC-721标准已就复仇引起了不可替代的令牌(NFT)市场。ERC-721是创建NFT的标准-一种表达“独特物品”的复杂方式。任何独特的事物都可以是NFT。一所房子,一张棒球卡,一件艺术品等。但是力量并不仅仅在于物品的独特性和数字化。力量在于可验证性。这就是ERC-721标准的亮点。


如何用IPFS构建ERC-721 NFT


  创建ERC-721令牌的问题来自存储基础资产。区块链不适用于存储大量数据。2017年,星际数据库的Jamila Omar估计在以太坊上存储1GB数据的成本将超过400万美元。


  总的来说,在以太坊上存储数据的成本约为17,500 ETH / GB,按今天的价格计算约为4,672,500美元。

  •贾米拉·奥马尔(Jamila Omar),2017年


  因此,如果我们知道存储与NFT绑定的资产的成本太高而无法使用区块链,那还有什么选择呢?我们可以使用传统的云存储来存储资产。亚马逊的S3和微软的Azure提供便宜的存储解决方案。但是,我们知道传统的云存储存在一个重大缺陷。

  这不是加密可验证的。


  可验证性

  NFT的重点是数字验证和对可能是实物或数字资产的控制。如果我们无法以类似于验证代表该资产的代币的所有权的方式来验证基础资产本身,那么我们将无法追踪最终目标。

  解决这两个问题的方法是IPFS。IPFS是一个分布式存储网络。它的工作方式与云存储类似。您请求内容,然后返回该内容。但是,最大的区别是内容是通过利用全球存储提供商网络来存储的。IPFS利用称为内容寻址能力的工具。这意味着,您不必向俄亥俄州的数据中心请求内容,而是要请求内容本身。它可能位于俄亥俄州。它可能位于更近的位置。借助内容可寻址性,您不再需要依赖单个位置来检索内容。对于全球区块链而言,这要高效得多。

  IPFS还负责我们的可验证性。因为所有内容都是基于内容本身定义和存储的,所以如果对某个内容进行篡改或更改,则在尝试验证内容并知道其错误时我们会出现不匹配的情况。让我们用一个简单的例子使它更加清楚:

  爱丽丝将猫的图片存储在IPFS上,并且该猫的图片由内容标识符表示。为了简单起见,假设标识符为“ C”。

  鲍勃要求那张猫的照片,然后在那只可怜的猫上画胡子。鲍勃上传照片时,他将不再具有相同的标识符。因为他已经更改了基础数据(从cat变为mustachioed cat),所以Bob的标识符可能是“ M”。

  如果鲍勃(Bob)试图假扮爱丽丝(Alice)的名义假扮自己的照片,那么任何愿意检查的人都会知道他在撒谎。爱丽丝的标识符与鲍勃的标识符不匹配,因此,由于爱丽丝的证伪是假冒的,鲍勃试图冒充的图像。


The Easiest Way to Use IPFS

  视频地址:https://youtu.be/6b8OANmw2kM


  我认为您可以在尝试验证NFT等数字资产时开始看到这一点。因此,考虑到这一点,让我们看看如何创建NFT并将关联的资产存储在IPFS上。


  入门

  对于本教程,您将需要一些注意事项:

  •一个好的文本编辑器

  •已安装IPFS

  •Ganache —以太坊的本地区块链—已安装

  •松露装

  •安装了NodeJS

  •皮纳塔API密钥

  您可以选择任何文本编辑器。我更喜欢Visual Studio Code,但这取决于您。

  确定编辑器后,请确保已安装IPFS。请直接从IPFS按照说明进行操作。

  当您将松露和Ganache放入完整的松露套件中时,您可以从同一位置抓取它们。

  如果您的计算机上还没有Node.js,则还需要下载。

  最后,您要确保为其创建NFT的贵重资产永久存储在IPFS上。可以通过运行自己的IPFS节点或使用所谓的IPFS固定服务来完成。为简单起见,我们将通过Pinata固定服务复制它。


  编写智能合约

  让我们在这里快速免责声明。我不是专业的智能合约开发商。我知道足够危险了,在区块链世界中,危险就等于赔钱。因此,请小心,进行研究,并确定最佳实践。本指南旨在作为一个教育的起点,也许有更好的方法来完成我在这里向您展示的内容。


  ERC-721令牌受智能合约约束。幸运的是,OpenZeppelin的员工可以确保您轻松编写良好的合同。我们将使用他们的ERC-721合同来帮助我们开始使用。

  首先,在您的终端中,创建一个新的项目文件夹。

  mkdir mySpecialAsset && cd mySpecialAsset

  接下来,我们将使用NPM初始化项目目录。

  npm init -y

  现在,我们可以利用Truffle初始化我们的智能合约项目。

  truffle init

  现在,我们需要获得那些甜美而甜美的Open Zeppelin合同。为此,我们将像这样安装Open Zeppelin的Solidity库:

  npm install @openzeppelin/contracts

  我们将需要为令牌创建一个好名字。我将其称为UniqueAsset,因为我们确保NFT必须与唯一的基础资产关联。您可以根据需要调用合同。我们希望将合同保存在合同文件夹中,因此我们将如下创建文件:

  touch contracts/UniqueAsset.sol


  现在,我们可以打开该文件并开始工作。我们需要指定版本(或与合同兼容的实体版本。我们还需要从Open Zeppelin导入合同框架。我们可以开始实施合同本身。让我们来看一下:

  语用强度^ 0.6.0

  导入“ @ openzeppelin / contracts / token / ERC721 / ERC721.sol”;

  导入“ @ openzeppelin / contracts / utils / Counters.sol”

  合同UniqueAsset是ERC721 {

  构造函数()公共ERC721(“ UniqueAsset”,“ UNA”){}

  }

  我们需要指定我们使用的Solidity版本。在这种情况下,我使用的是0.6.0。您可以通过编辑truffle-config.js文件来确保Truffle使用正确版本的Solidity编译合同。我正在从Open Zeppelin导入两个合同:ERC721和Counters。计数器只是在发行后帮助我们增加令牌ID。最后,在合同的构造函数中,我们定义了令牌名称和符号。同样,您可以将其设置为您想要的任何值。


  我们将需要在合同中添加一些逻辑。现在开始吧。

  首先,让我们考虑一下我们要在这里做什么。我们要为特定资产发行NFT。我们希望这些资产可验证,就像我们希望所有权可验证一样。因此,我们需要在此处考虑以下几点:

  1、我们希望将NFT与IPFS内容标识符(哈希)相关联。

  2、我们永远不想铸造(或创建)与另一个NFT映射到相同IPFS哈希的NFT。

  让我们从在合同中定义变量开始,我们将使用这些变量来控制上述两点。在合同代码中的构造函数上方,添加以下内容:

  使用Counters for Counters.Counter;

  Counters.Counter私有_tokenIds;

  mapping(string => uint8)哈希;

  constructor()public ERC721(“ UniqueAsset”,“ UNA”){}

  ...

  我们正在使用计数器来帮助我们增加我们铸造的令牌的标识符。我们还创建了一个_tokenIds变量来跟踪我们已发行的所有令牌。最后,对于顶级变量,我们正在为与令牌关联的IPFS哈希创建映射。这将有助于防止发行令牌映射到先前与另一个令牌相关联的哈希。

  您的合同现在应如下所示:

  语用强度^ 0.6.0

  导入“ @ openzeppelin / contracts / token / ERC721 / ERC721.sol”;

  导入“ @ openzeppelin / contracts / utils / Counters.sol”;

  合同UniqueAsset是ERC721 {

  使用Counters for Counters.Counter;

  Counters.Counter私有_tokenIds;

  mapping(string => uint8)哈希;

  constructor()公共ERC721(“ UniqueAsset”,“ UNA”){}

  }


  我们需要在合同中添加一种方法,该方法将允许我们为特定的IPFS哈希值铸造NFT(如果尚未为该哈希值铸造令牌)。我们将在构造函数的下方进行此操作。

  函数awardItem(地址接收者,字符串存储哈希,字符串存储元数据)

  公共

  返回(uint256)

  {

  require(哈希[哈希]!= 1);

  哈希值[hash] = 1;

  _tokenIds.increment();

  uint256 newItemId = _tokenIds.current();

  _mint(收件人,newItemId);

  _setTokenURI(newItemId,元数据);

  返回newItemId;

  }


  这里有很多事情,所以让我们逐行介绍。我们的函数有两个参数:一个地址变量称为recipient,一个字符串变量称为hash和一个字符串变量metadata。地址变量是将接收NFT的人员的钱包地址。的字符串变量hash是与我们为其创建NFT的内容相关联的IPFS哈希。的字符串变量metadata应指向资产的JSON元数据的链接。元数据可能包括资产名称,指向引用该资产的图像的链接或您想要的其他任何内容。

  然后,在定义我们的功能之后,我们将其制成public。这只是意味着可以从智能合约外部调用它。我们还将函数的返回值定义为type uint256

  在该函数内部,require如果以前使用散列来创建NFT ,我们将使用Solidity的内置函数自动拒绝合同调用。您会注意到我们正在检查hashes映射是否具有匹配的哈希,该哈希的整数为1。如果是,则使用该哈希。

  如果尚未使用哈希,则将通过函数传递的哈希添加到哈希映射中,并将其值设置为1)。

  最后,我们将增加_tokenIds变量,因为我们将要创建一个新的NFT并铸造令牌,并返回令牌标识符。

  太多了,所以让我们快速总结一下而不必依赖代码。现在我们的合同接受一个人的以太坊钱包地址和IPFS哈希。它检查以确保哈希值与先前铸造的NFT不匹配。如果一切正常,则将针对该IPFS哈希创建一个新的NFT。

  好的,我们已经写好了合同。怎么办?

  让我们对其进行编译和部署。记得我曾问过您安装Ganache。我们现在要使用它。通过ganache-cli或使用桌面客户端(我更喜欢桌面客户端)启动Ganache 。

  如果您在项目目录中浏览,则会看到一个名为的文件夹migrations。我们需要创建一个新的迁移文件。这些文件非常具体,在这种情况下,我们需要它在默认情况下为您创建的现有迁移文件之后运行。为确保这种情况发生,我们将在迁移文件2的开头以a命名。继续并致电您的新迁移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文件中,您可以找到该networks部分并适当设置开发网络端口。

  如果一切顺利,您只需部署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。该目录可以与您创建智能合约的目录相同。在编写代码之前,最好准备好资产文件。只要确保将其保存在您使用的计算机上的某个位置即可。对我来说,我要上传儿子做的一幅画:


儿子做的画


  现在我们已经保存了资产并准备上传,让我们编写代码。我们需要两个依赖关系,以使我们更容易做到这一点。在终端的项目根目录中,运行以下命令:

  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 =等待axios.post(URL,data,{

  maxContentLength:“ Infinity”,

  标头:{

  “ 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,

  时间戳:'2020-12-03T21:07:13.876Z'

  }

  该哈希值是您资产的可验证表示。它指向IPFS网络上的资产。如果有人篡改了您的资产并进行了更改,则哈希值将有所不同。通过我们的智能合约创建NFT时应使用该哈希。任何提供公共网关的IPFS主机现在都可以为您显示内容。

  Pinata有一个网关,您可以在这里查看我刚刚上传的资产。

  我们需要做的最后一件事是创建一个代表我们的资产及其元数据的JSON文件。这使您可能希望列出资产以显示适当的元数据的任何服务都更加容易。让我们创建一个简单的JSON文件,如下所示:

  {

  “名称”:“我的孩子的艺术”,

  “哈希”:“ QmfAvnM89JrqvdhLymbU5sXoAukEJygSLk9cJMBPTyrmxo”,

  “作者”:“ Justin Huner”

  }

  您可以添加任何想要的元数据,但是包含哈希值很重要。这是对实际资产的参考。现在,以与使用Pinata上传资产文件相同的方式上传此文件。当您获取元数据的IPFS哈希值时,请保持方便。创建令牌时需要使用它。

  还记得吗,智能合约需要一个元数据字符串?该字符串将成为元数据的IPFS URL。您将像这样构造它:

  ipfs://YOUR_METADATA_HASH

  综上所述,您将把三个项目传递到我们先前创建的智能合约功能中:

  •收件人地址

  •资产哈希

  •元数据网址


  汇集全部

  NFT是我们处理各种商品所有权的方式的一项重要改进。它们易于转让,并简化了创建所有权和证明所有权的过程。但是,缺少的部分是对特定项目所有权的验证。

  通过将资产保存到IPFS并将IPFS哈希与资产的NFT相关联,我们可以扩展资产的可验证所有权以验证资产本身的有效性。

  Pinata通过简化IPFS上的资产存储来帮助简化此过程。


最新推荐