您的位置:首页 >财经 >

新手入门:如何使用Flow和IPFS创建类似NBA Top Shot的NFT

2021-03-10 18:47:46来源:金色财经

随着非同质化代币NFT市场进入狂热的阶段,回顾相对早期的NFT并记住CryptoKitties所面临的挑战是一件有趣的事情。Dapper Labs团队构建的平台是第一个潜在大规模采用的真实示例,也是以太坊区块链上的第一个真正压力。

从那以后,随着Rarible、OpenSea、Foundation和Sorare等平台的涌现,NFT开始蓬勃发展。这些平台每月都有数百万美元的资金流入。尽管早期存在一些困难,但大多数情况已经在以太坊区块链上发生了。但是,Dapper Labs的团队在经历了CryptoKitties之后,开始着手构建一个通用的新区块链,但也非常适合 NFT用例。这样做的目的是解决在以太坊上所遇到的许多NFT问题,同时为该领域的开发者和收藏家提供更好的体验。他们的新区块链Flow已经证明自己有能力获得一些知名度。NBA、UFC甚至Dr. Seuss都在使用Flow。

我们最近写了一篇关于在IPFS上创建具有内置资产支持的NFT的文章,并且讨论了NFT领域中的责任问题,以及我们认为IPFS可以提供的帮助。现在是时候讨论如何在IPFS支持的Flow上创建NFT。Flow区块链的主要早期应用是NBA Top Shot。我们将创建一个非常基本的铸造NFT过程的副本,然后在IPFS上备份NFT元数据和资产。

由于我们喜欢piñatas,而不是NBA的精彩视频,因此我们的NFT将专注于可交易性piñatas在派对上被销毁的视频。

本教程由三个部分组成

创建合约并铸造代币。

创建一个应用程序来查看通过此合约创建的NFT。

创建一个市场,将NFT转让给其他人,同时在IPFS上转让NFT的基础资产

让我们从第一个教程开始。

设置

我们需要安装Flow CLI。在Flow的文档中有一些很好的安装说明,但我将在这里复制它们:

ios系统

brew install flow-cli

Linux操作系统

sh -ci “$(curl -fsSL https://storage.googleapis.com/flow-cli/install.sh)"

Windows系统

iex “& { $(irm ‘https://storage.googleapis.com/flow-cli/install.ps1") }”

我们将在IPFS上存储资产文件。为了简化操作,我们可以使用Pinata。您可以在这里注册一个免费帐户,然后在这里获取一个API密钥。

我们还需要安装NodeJS和文本编辑器,以帮助突出显示Flow智能合约代码的语法(以Cadence语言编写的)。您可以在此处安装Node。Visual Studio Code具有支持Cadence的扩展。

让我们创建一个目录来记录我们的项目。

mkdir pinata-party

切换到该目录并初始化新的Flow项目:

cd pinata-partyflow project init

现在,在您最喜欢的代码编辑器中打开项目(同样,如果您使用的是Visual Studio code,请获取Cadence扩展),然后开始工作。

您会看到一个flow.json文件,我们将很快使用它。首先,创建一个名为cadence的文件夹。在该文件夹中,添加另一个名为contracts的文件夹。最后,在contracts文件夹中创建一个名为PinataPartyContract.cdc的文件。

在我们继续前进之前,重要的是要指出,从现在开始,我们对Flow区块链所做的一切都将在模拟器上完成。然而,将项目部署到测试网或主网就像更新flow.json文件中的配置设置一样简单。现在将文件设置为模拟器环境,然后我们就可以开始编写合约了。

更新flow.json中的合约对象,如下文所示:

"contracts": {     "PinataPartyContract": "./cadence/contracts/PinataPartyContract.cdc"}

然后,将该文件中的deployments对象更新为如下文所示:

"deployments": {     "emulator": {          "emulator-account": ["PinataPartyContract"]     }}

这是告诉Flow CLI使用模拟器来部署我们的合约,它还引用了(模拟器上的)帐户和我们即将编写的合约。实际上……

让我们开始写这个合约吧。

合约

Flow提供了关于创建NFT合约的出色教程。这是一个很好的参考点,但是正如Flow所指出的,他们尚未解决NFT元数据问题。他们希望将元数据存储在链上。这是个好主意,他们肯定会想出一个合乎逻辑的方法。然而,我们现在想用元数据铸造一些代币,并且我们想要与NFT相关联的媒体文件。元数据只是一个组成部分。我们还需要指向代币最终代表的媒体。

如果您熟悉以太坊区块链上的NFT,您可能知道这些代币背后的许多资产存储在传统数据存储和云托管提供商中。这是可以的,除非它不是。我们过去曾写过关于内容寻址内容的天才,以及在传统云平台上存储与区块链相邻数据的弊端。这一切归结为两点:

资产应该是可验证的

应该很容易转移维护职责

IPFS解决了这两个问题。然后,Pinata以一种简单的方式分层,将该内容长期固定在IPFS上。这正是我们希望支持NFT的媒体所需要的,对吧?我们希望确保我们能够证明所有权(NFT),提供关于NFT的数据,并确保我们对基础资产(IPFS)具有控制权,而不是一些副本。

打开PinataPartyContract.cdc,让我们开始工作。

第一步是定义我们的合约。我们将在此基础上添加更多内容,但我们从自定义PinataPartyContract开始,并在其中创建一个资源。资源是存储在用户帐户中的项目,并可以通过访问控制措施进行访问。在这种情况下,NFT资源最终是因为用于表示NFT的东西拥有。NFT必须是唯一可识别的。该id属性使我们能够识别代币。

接下来,我们需要创建一个资源接口,该接口将用于定义哪些功能可供给其他人使用(例如,不是合约所有者的人):

将其放在NFT资源代码的正下方。这个NFTReceiver资源接口表示,我们定义的任何可以访问该资源的人都可以调用以下方法:

存款

获取ID

理想主义者

获取元数据

接下来,我们需要定义代币收集接口。可以将其视为容纳所有用户NFT的钱包。

这个资源中有很多内容,但是很快就会有意义。首先,我们有一个名为ownedNFTs的变量。这很简单。它跟踪该合约中用户拥有的所有NFT。

接下来,我们有一个名为metadataObjs的变量。这一点有点独特,因为我们扩展了Flow NFT合约功能,以存储每个NFT的元数据映射。这个变量将代币ID映射到其关联的元数据,这意味着在设置代币id之前需要该代币ID。

然后,我们初始化变量。这对于在Flow的资源中定义的变量是必需的。

最后,我们拥有NFT收集资源的所有可用功能。请注意,并非所有这些功能都可以使用。如果您还记得,我们在NFTReceiver资源接口中定义了任何人都可以访问的功能。

我想指出存款功能。就像我们扩展了默认的Flow NFT合约以包含metadataObjs映射一样,我们也扩展了默认的deposit功能以获取额外的元数据参数。我们为什么要这样做?我们需要确保只有代币的铸造者才能将元数据添加到代币中。为了保持这种私密性,我们将初始的元数据添加限制在铸造执行中。

我们几乎完成了合约代码。因此,在Collection资源的正下方,添加以下内容:

首先,我们有一个功能,该功能在调用时创建一个空的NFT集合。这就是首次与我们的合约交互的用户创建存储位置的方式,该存储位置映射到我们定义的资源存储位置。

之后,我们再创建一个资源。这很重要,因为没有它,我们将无法铸造代币。NFTMinter资源包括一个idCount,以确保我们的NFT永远不会有重复的ID。它还具有实际创建NFT的功能。

在NFTMinter资源的正下方,添加主合约初始化程序:

仅在部署合约时才调用此初始化函数。它有三个功能:

1.为集合的部署者创建一个空集合,以便合约的所有者可以从该合约中创建并拥有该NFT。

2.集合资源发布在公共位置,并引用我们在开始时创建的NFTReceiver接口。这就是我们告诉合约NFTReceiver上定义的函数可以被任何人调用的方式。

3.NFTMinter资源保存在帐户存储中,供合约创建者使用。这意味着只有合约的创建者才能铸造代币。

完整的合约可以在这里找到。

现在我们已经准备好了一个合约,让我们来部署它,对吗?我们应该在Flow Playground上对其进行测试。看那里,点击左边栏的第一个帐户。用我们的合约代码替换示例合约中的所有代码,然后单击“部署”。如果一切顺利,您应该会在屏幕底部的日志窗口中看到这样的日志:

16:48:55 Deployment Deployed Contract To: 0x01

现在,我们准备将合约部署到本地运行的模拟器。 在命令中,运行以下命令:

flow project start-emulator

现在,在我们的模拟器运行且正确配置了flow.json文件的情况下,我们可以部署合约了。只需运行以下命令:

flow project deploy

如果一切顺利,您将看到以下输出:

Deploying 1 contracts for accounts: emulator-accountPinataPartyContract -> 0xf8d6e0586b0a20c7

现在,我们在Flow模拟器上有一个合约,但是我们想要铸造一个代币。让我们以这个话题来结束这篇文章。

铸造NFT

在本教程的第二篇文章中,我们将致力于通过应用程序和用户界面使铸造过程更加友好。为了更好地理解并展示元数据如何在Flow上与NFT一起使用,我们将使用Cadence脚本和命令操作。

让我们在pinata-party项目的根目录中创建一个新目录,并将其称为transactions。创建了该文件夹后,在其中创建一个名为mintpinatparty .cdc的新文件。

为了编写交易,我们需要在我们提供给NFT的元数据中引用一个文件。为此,我们将通过Pinata上传一个文件到IPFS。出于本教程的目的,也因为我们的NFT专注于在派对上被砸的piñata的可交易视频,您可以上传一个孩子在生日聚会上敲击piñata的视频。您可以上传任何所需的视频文件。您可以上传所需的任何资产文件,并将其与您的NFT关联,但本教程系列的第二篇文章将会提供视频内容。一旦您准备好了视频文件,请在这里上传。

上传文件后,系统将提供一个IPFS哈希(通常称为内容标识符或CID)。复制此哈希,因为我们将在铸造过程中使用它。

现在,在你的MintPinataParty.cdc文件中,添加以下内容:

这是一个非常简单的交易,这在很大程度上归功于Flow简化了工作,使事情变得容易,但是让我们来看看它。首先,您将注意到顶部的import语句。如果您还记得,当我们部署合约时,我们收到了一个账户。这是我们需要参考的。因此,将0xf8d6e0586b0a20c7替换为部署时的帐户地址。

接下来我们定义交易。这里发生的所有事情都与我们计划执行的交易相关。

我们在交易中做的第一件事是定义两个引用变量receiverRef和mininterref。在这种情况下,我们既是NFT的接受者,也是NFT的执行者。这两个变量引用了我们在合约中创建的资源。如果执行交易的人没有访问资源的权限,则交易将失败。

接下来,我们有一个prepare功能。该功能获取尝试执行交易的人的帐户信息,并进行一些验证。我们试图“借用”定义的NFTMinter和NFTReceiver这两个资源上的可用功能。如果执行交易的人无法访问这些资源,那么交易就会失败。

最后,我们有execute功能。在这个功能中,我们为NFT构建元数据,铸造NFT,然后在将NFT存入我们的帐户之前关联元数据。如果您注意到了,我创建了一个元数据变量。在这个变量中,我添加了一些关于我们的代币的信息。由于我们的代币表示的是一个piñata在派对上被打碎的事件,而且我们试图复制您在NBA Top Shot中看到的大部分内容,所以我在元数据中定义了一些统计数据。孩子挥杆击中piñata的速度、挥杆的角度和等级。我只是觉得这些数据很有趣。不过,您可以以类似的方式为您的代币输入有意义的任何信息。

您将注意到,我还在元数据中定义了一个uri属性。这将指向托管与NFT相关联的资产文件的IPFS哈希。在这种情况下,被击中的是piñata的实际视频。您可以用先前上传文件后收到的哈希值替换哈希值

我们在哈希前加上ipfs://有几个原因。这是IPFS上对文件的正确引用,可以与IPFS的桌面客户端和浏览器扩展一起使用。既然Brave浏览器提供了对IPFS内容的本机支持,我们也可以直接将其粘贴到Brave浏览器中。

我们调用铸造代币的mintNFT函数。然后我们必须调用存款功能来将其存入我们的帐户。这也是我们传递元数据的地方。如果您还记得,我们在存款功能中定义了一个变量关联,它将元数据添加到相关的代币ID。

最后,我们只需注销已铸造和存放代币的事实。

现在,我们几乎已经准备好发送交易并铸造NFT。但是首先,我们需要准备我们的账户。在项目的根文件夹中,从命令行创建一个新的私钥进行签名。

执行以下命令:

flow keys generate

这将为您提供一个公钥和一个私钥。**始终保护您的私钥**

我们将需要私钥来签署交易,因此我们可以将其粘贴到我们的flow.json文件中。我们还需要指定签名算法。以下是您的帐户在flow.json文件现在应该是这样的:

"accounts": {  "emulator-account": {     "address": "YOUR ACCOUNT ADDRESS",     "privateKey": "YOUR PRIVATE KEY",     "chain": "flow-emulator",     "sigAlgorithm": "ECDSA_P256",     "hashAlgorithm": "SHA3_256"  }},

如果打算将该项目中的任何一个存储在github或任何远程git存储库上,请确保不包括私钥。您可能想要.gitiignore您的整个flow.json。尽管我们只使用本地模拟器,但保护密钥是一个很好的做法。

现在我们已经更新了此信息,我们可以发送交易。这样做就像运行以下命令一样简单:

flow transactions send --code ./transactions/MintPinataParty.cdc --signer emulator-account

我们从flow.json引用我们写的交易文件和签名者帐户。如果一切顺利,您应该会看到以下输出:

Getting information for account with address 0xf8d6e0586b0a20c7 ...Submitting transaction with ID 4a79102747a450f65b6aab06a77161af196c3f7151b2400b3b3d09ade3b69823 ...Successfully submitted transaction with ID 4a79102747a450f65b6aab06a77161af196c3f7151b2400b3b3d09ade3b69823

现在,我们需要做的最后一件事是验证代币是否在我们的帐户中,并获取元数据。要做到这一点,我们将编写一个非常简单的脚本,并从命令行调用它。

在项目的根目录下,创建一个名为scripts的新文件夹。在其中,创建一个名为CheckTokenMetadata.cdc的文件。在该文件中,添加以下内容:

这个脚本可以用类似于使用以太坊智能合约的只读方法的方式来考虑。它们是免费的,只是从合约中返回数据。 

在我们的脚本中,我们从部署的地址导入合约。然后我们定义一个主要功能(这是运行脚本所需的函数名称)。在这个函数中,我们定义了三个变量: 

nftOwner:这只是拥有NFT的帐户。我们从部署合约的帐户中创建了NFT,因此在我们的示例中,取决于将来的合约设计,这可能并不总是正确的。

功能:我们需要从部署的合约中“借用”可用的能力(或功能)。请记住,这些功能是受访问控制的,因此,如果某个功能不能被试图借用它的地址使用,那么脚本将失败。我们借用了NFTReceiver资源的功能。

receiverRef:这个变量简单地获取我们的功能,并告诉脚本从部署的合约中借用。

现在,我们可以调用(可用的)函数。在这种情况下,我们希望确保所涉及的地址确实收到了我们铸造的NFT,然后我们希望看到与代币关联的元数据。

让我们运行我们的脚本,看看我们得到了什么。在命令行中执行以下命令:

flow scripts execute ./scripts/CheckTokenMetadata.cdc

对于元数据输出,您会看到类似以下的输出:

{"name": "The Big Swing", "swing_velocity": "29", "swing_angle": "45", "rating": "5", "uri": "ipfs://QmRZdc3mAMXpv6Akz9Ekp1y4vDSjazTx2dCQRkxVy1yUj6"}

恭喜您!您成功地创建了一个Flow智能合约、铸造了一个代币,并将元数据关联到代币,并将代币的底层数字资产存储在IPFS上。对于教程的第一部分来说还不错。

接下来,我们将提供一个关于构建前端React应用程序的教程,该应用程序将允许你通过获取元数据并解析该元数据来显示您的NFT。

祝您好运!