随着NFT将区块链带入公众视野,现在是一个极好的机会,通过在以太坊区块链上发布自己的NFT(ERC-721代币)来宣传自己。

Alchemy 非常自豪能够为NFT领域的大公司提供支持,包括Makersplace(最近在佳士得创造了6900万美元的数字艺术品销售记录)、Dapper Labs(NBA Top Shot & Crypto Kitties的创造者)、OpenSea(世界上最大的NFT市场)、Zora、Super Rare、NFTfi、基金会、Enjin、Origin Protocol、Immutable等等。

在本教程中,我们将通过使用MetaMaskSolidityHardhatPinataAlchemy在Ropsten测试网络上创建和部署一个ERC-721智能合约。

在本教程的第二部分,将讨论如何使用我们的智能合约来铸造一个NFT,在第三部分,我们将解释如何在MetaMask上查看你的NFT。

当然,如果你在任何时候有问题,不要犹豫,请联系Alchemy Discord或访问Alchemy的NFT API文档!

第1步:连接到以太坊网络

有一堆方法可以向以太坊区块链提出请求,但为了方便起见,我们将使用Alchemy上的免费账户,这是一个区块链开发者平台和API,允许我们与以太坊链进行通信,而无需运行我们自己的节点。

在本教程中,我们还将利用Alchemy 开发者工具进行监控和分析,以了解我们的智能合约部署中的幕后情况。如果你还没有Alchemy账户,你可以免费注册这里

第2步:在Alchemy你创建应用获取API密钥

一旦你创建了Alchemy账户,你可以通过创建一个应用程序来生成一个API密钥。我们通过API密钥向Ropsten测试网络发出请求。如果你想了解更多关于测试网络的信息,请查看本指南

  1. 导航到Alchemy仪表板的 Create App页面,将鼠标悬停在导航栏的 App 上,并点击 Create App

创建你的应用程序

  1. 为你的应用命名(我们使用 My First NFT!),提供一个简短的描述,环境选择 Staging,并为你的网络选择 Ropsten

配置应用

  1. 点击 Create app,就可以了! 你的应用应该出现在下面的表格中。

第3步:创建一个以太坊账户(地址)

我们需要一个以太坊账户来发送和接收交易。在本教程中,我们将使用MetaMask,这是一个浏览器中的虚拟钱包,用于管理你的以太坊账户地址。

你可以免费下载MetaMask并创建一个账户。或者如果你已经有一个账户,确保切换到右上方的 Ropsten测试网络(这样我们就不用花费真的以太币)。

设置Ropsten为你的网络

第4步:从水龙头添加以太币

为了将我们的智能合约部署到测试网络,我们需要一些假的ETH。你可以去FaucETH获得ETH,输入你的Ropsten账户地址,点击 Request funds,然后在下拉菜单中选择 Ethereum Testnet Ropsten,最后再次点击 Request funds 按钮。你应该很快在你的MetaMask账户中看到收到的ETH!

第5步:检查你的余额

为了再次确定我们的余额,让我们使用Alchemy的composer工具做一个eth_getBalance请求。这将返回我们钱包中的ETH数量。在你输入你的MetaMask账户地址并点击 发送请求 后,你应该看到一个像这样的响应:

{"jsonrpc": "2.0", "id": 0, "result": "0xde0b6b3a7640000"}
  • 注意: 余额的结果返回以 wei 为单位,而不是 eth, Wei 是以太币的最小单位,转换关系是: 1 eth = 1018 wei. 因为如果我们转换 0xde0b6b3a7640000 为 10 进制,者是 1*1018 , 等于 1 ETH(这个测试网上的假币).

第6步: 初始化工程

首先,我们需要为项目创建一个文件夹。导航到命令行并输入:

mkdir my-nft
    cd my-nft

现在我们进入了项目文件夹,我们将使用npm init来初始化项目。如果你还没有安装npm,按照这个说明(我们还需要Node.js,所以也下载它!)

npm init

初始化项目时,需要进行一些设置,以回答问题的方式设置,如何回答安装问题并不重要,以下是我们的做法,以供参考:

package name: (my-nft)
    version: (1.0.0)
    description: My first NFT!
    entry point: (index.js)
    test command:
    git repository:
    keywords:
    author:
    license: (ISC)
    About to write to /Users/thesuperb1/Desktop/my-nft/package.json:
    
    {
      "name": "my-nft",
      "version": "1.0.0",
      "description": "My first NFT!",
      "main": "index.js",
      "scripts": {
        "test": "echo \"Error: no test specified\" && exit 1"
      },
      "author": "",
      "license": "ISC"
    }

第7步: 安装 Hardhat

Hardhat是一个开发环境,用于编译、部署、测试和调试你的以太坊软件。它可以帮助开发者在部署到真实链之前在本地构建智能合约和dApps。

在我们的my-nft项目中运行:

npm install --save-dev hardhat

查看这个页面,了解更多关于安装说明的细节。

第8步:创建Hardhat项目

在我们的项目文件夹中运行:

npx hardhat

然后你应该看到一个欢迎信息和选择你想做什么的选项。这里选择 Create an empty hardhat.config.js

888    888                      888 888               888
    888    888                      888 888               888
    888    888                      888 888               888
    8888888888  8888b.  888d888 .d88888 88888b.   8888b.  888888
    888    888     "88b 888P"  d88" 888 888 "88b     "88b 888
    888    888 .d888888 888    888  888 888  888 .d888888 888
    888    888 888  888 888    Y88b 888 888  888 888  888 Y88b.
    888    888 "Y888888 888     "Y88888 888  888 "Y888888  "Y888
    Welcome to Hardhat v2.0.11 
    ? What do you want to do? …
    Create a sample project
    ❯ Create an empty hardhat.config.js
    Quit

这将为我们生成一个hardhat.config.js文件,在这里我们将为项目指定所有的设置(见步骤13)

第9步:添加项目文件夹

为了使我们的项目有条理,我们将创建两个新的文件夹。在你的命令行中导航到项目的根目录,然后输入:

mkdir contracts
    mkdir scripts
  • contracts/ 是我们保存NFT智能合约代码的地方
  • scripts/ 是我们保存脚本的地方,用于部署和与我们的智能合约进行交互。

第10步:编写我们的合约

现在我们的环境已经设置好了,接下来是更令人兴奋的事情。编写我们的智能合约代码!

在你喜欢的编辑器(我们喜欢VSCode)中打开my-nft项目。智能合约是用一种叫做Solidity的语言编写的,我们将用它来编写我们的MyNFT.sol智能合约。

  1. 导航到contracts文件夹,并创建一个名为MyNFT.sol的新文件。
  2. 下面是我们的NFT智能合约代码,我们基于OpenZeppelin库的ERC-721实现。复制并粘贴以下内容到你的MyNFT.sol文件中:
//Contract based on [https://docs.openzeppelin.com/contracts/3.x/erc721](https://docs.openzeppelin.com/contracts/3.x/erc721)
   // SPDX-License-Identifier: MIT
   pragma solidity ^0.8.0;

   import "@openzeppelin/contracts/token/ERC721/ERC721.sol";
   import "@openzeppelin/contracts/utils/Counters.sol";
   import "@openzeppelin/contracts/access/Ownable.sol";
   import "@openzeppelin/contracts/token/ERC721/extensions/ERC721URIStorage.sol";

   contract MyNFT is ERC721URIStorage, Ownable {
       using Counters for Counters.Counter;
       Counters.Counter private _tokenIds;

       constructor() ERC721("MyNFT", "NFT") {}

       function mintNFT(address recipient, string memory tokenURI)
           public onlyOwner
           returns (uint256)
       {
           _tokenIds.increment();

           uint256 newItemId = _tokenIds.current();
           _mint(recipient, newItemId);
           _setTokenURI(newItemId, tokenURI);

           return newItemId;
       }
   }
  1. 因为我们要从OpenZeppelin合约库中继承基础合约类,在你的命令行中运行npm install @openzeppelin/contracts来把这个库安装到我们的工程中。

那么,上面这段代码到底做了什么?让我们逐行分解:

在我们的智能合约的顶部,我们导入了三个OpenZeppelin智能合约类:

  • @openzeppelin/contracts/token/ERC721/ERC721.sol 包含ERC-721标准的实现,我们的NFT智能合约将继承这个标准。(要成为一个有效的NFT,你的智能合约必须实现ERC-721标准的所有方法)。要了解更多关于继承的ERC-721功能,请查看接口定义这里
  • @openzeppelin/contracts/utils/Counters.sol 提供了只能加 1或减1 的计数器。我们的智能合约使用计数器来跟踪已铸币的NFT总数,并在我们的新NFT上设置唯一的ID。(每个使用智能合约铸造的NFT必须被分配一个唯一的ID-- 在本文案例中,我们的唯一ID只是由存在的NFT总数决定。例如,我们用智能合约铸造的第一个NFT的ID是 1,我们的第二个NFT的ID是 2,等等)。
  • @openzeppelin/contracts/access/Ownable.sol在我们的智能合约上设置了访问控制,所以只有智能合约的所有者(你)可以铸币NFT。(注意,包括访问控制完全是一种偏好。如果你希望任何人都能使用你的智能合约铸造NFT,请删除第10行的Ownable一词和第17行的onlyOwner)。

在我们的导入语句之后,我们有了自定义的NFT智能合约,它出乎意料地短 -- 它只包含一个计数器、一个构造函数和一个函数!这要归功于我们继承的OpenZeppelin合约,它实现了我们需要创建NFT的大部分方法,,例如ownerOf,它返回NFT的所有者,以及transferFrom,它将NFT的所有权从一个账户转移到另一个账户。

在我们的ERC-721构造函数中,你会注意到我们传递了两个字符串,MyNFT 和 NFT。第一个变量是智能合约的名称,第二个是其符号。你可以随心所欲地给这些变量命名!

最后,我们有我们的函数mintNFT(address recipient, string memory tokenURI),用来铸造一个NFT,你会注意到这个函数接收了两个变量:

  • address recipient指定将收到你新铸的NFT的地址
  • string memory tokenURI是一个字符串,应该解析为一个描述NFT元数据的JSON文档。NFT的元数据实际上是给它带来生命的东西,允许它有可配置的属性,如名称、描述、图像和其他属性。在本教程的第二部分,我们将描述如何配置这个元数据。

mintNFT 从继承的ERC-721库中调用一些方法,并最终返回一个数字,代表新铸造的 NFT 的ID。

第11步:在项目配置MetaMask和Alchemy

现在我们已经创建了MetaMask钱包、Alchemy账户,并编写了我们的智能合约,现在是时候连接这三者了。

从你的虚拟钱包发出的每一笔交易都需要使用你独特的私钥进行签名。为了向我们的程序提供这种许可,我们可以在环境文件中安全地存储我们的私钥(和Alchemy API密钥)。

要了解更多关于发送交易的信息,请查看本教程关于使用web3发送交易。

首先,在你的项目目录下安装dotenv包。

npm install dotenv --save

然后,在我们项目的根目录下创建一个.env文件,将你的MetaMask私钥和HTTP Alchemy API URL加入到文件中。

  • 按照这些说明,从MetaMask导出你的私钥
  • 请看下面的说明,以获得HTTPAlchemyAPI URL,并将其复制到你的剪贴板上

Copy your Alchemy API URL

.env 文件的内容类似:

API_URL="https://eth-ropsten.alchemyapi.io/v2/your-api-key"
    PRIVATE_KEY="your-metamask-private-key"

要将这些变量实际连接到我们的代码,我们将在步骤13中修改hardhat.config.js文件中来引用这些变量。

不提交 .env , 请确保不要共享或公开 .env 文件,因为这样做会泄露你的密钥 。如果使用版本控制,请添加 .env 到 .gitignore 文件里。

第 12 步: 安装 Ethers.js

Ethers.js是一个库,通过更友好的方法包装标准JSON-RPC方法,以便用户更容易与以太坊链进行交互。

Hardhat 通过集成插件的方式非常容易就可以获得额外的工具和功能扩展。我们将利用Ethers插件进行合约部署(Ethers.js有一些很简洁的合约部署方法)。

在项目目录下输入以下命令以安装Ethers.js:

npm install --save-dev @nomiclabs/hardhat-ethers ethers@^5.0.0

在下一步中,我们还将在 hardhat.config.js 中ethers。

第 13 步: 修改hardhat.config.js

前面,我们已经添加了几个依赖和插件,现在需要更新hardhat.config.js,以便项目知道所有相关的配置和插件。

更新hardhat.config.js,使其看起来像这样:

/**
    * @type import('hardhat/config').HardhatUserConfig
    */
    require('dotenv').config();
    require("@nomiclabs/hardhat-ethers");
    const { API_URL, PRIVATE_KEY } = process.env;
    module.exports = {
       solidity: "0.8.1",
       defaultNetwork: "ropsten",
       networks: {
          hardhat: {},
          ropsten: {
             url: API_URL,
             accounts: [`0x${PRIVATE_KEY}`]
          }
       },
    }

第14步:编译合约

为了确保到目前为止一切正常,让我们来编译合约。编译任务是内置的Hardhat任务之一。

在命令行上运行:

npx hardhat compile

你可能会得到一个关于源文件中没有提供SPDX许可证标识符的警告,但不需要担心这个问题。

第15步: 编写部署脚本

现在我们的合约已经写好了,我们的配置文件也可以使用了,现在是时候写我们的合约部署脚本了。

进入到scripts/文件夹,创建一个名为deploy.js的新文件,添加以下内容:

async function main() {
  const MyNFT = await ethers.getContractFactory("MyNFT")

  // Start deployment, returning a promise that resolves to a contract object
  const myNFT = await MyNFT.deploy()
  await myNFT.deployed()
  console.log("Contract deployed to address:", myNFT.address)
}

main()
  .then(() => process.exit(0))
  .catch((error) => {
    console.error(error)
    process.exit(1)
  })

Hardhat在合约教程中对这些代码的每一行都做了很好的解释,我们在这里采用了他们的解释。

const MyNFT = await ethers.getContractFactory("MyNFT");

ethers.js中的ContractFactory是一个用于部署新智能合约的抽象,所以这里的MyNFT是我们NFT合约实例的工厂。当使用hardhat-ethers插件时,ContractFactory和合约实例默认连接到第一个签名者。

const myNFT = await MyNFT.deploy();

在ContractFactory上调用deploy()将开始部署,并返回一个解析为Contract的Promise。这是一个对象,为智能合约的每个功能都有一个对应的方法。

第16步:部署合约

我们终于准备好部署我们的智能合约了! 回到项目根目录,并在命令行中运行:

npx hardhat --network ropsten run scripts/deploy.js

然后你应该看到类似这样的提示:

Contract deployed to address: 0x81c587EB0fE773404c42c1d2666b5f557C470eED

如果去Ropsten etherscan并搜索合约地址,我们应该能够看到它已经被成功部署。如果你不能立即看到它,请等待一段时间,因为它可能需要一些时间。该交易将看起来像这样。

在Etherscan上查看您的交易地址

From地址应与你的MetaMask账户地址一致,收件人地址将显示为 Contract Creattion(合约创建)。如果我们点击进入交易,我们会在To字段下看到我们的合约地址。

在Etherscan上查看您的合约地址

耶~,你刚刚把你的NFT智能合约部署到了以太坊链上!

为了了解背后的交易的情况,让我们浏览一下Alchemy dashboard, 如果你有多个Alchemy应用,请确保按应用过滤并选择 "MyNFT"。

使用Alchemy的资源管理器仪表板查看 "引擎 "下的调用

在这里,你会看到Hardhat/Ethers在我们调用.deploy()函数时,在交易背后为我们发起的的少量JSON-RPC调用。这里有两个重要的调用是 eth_sendRawTransaction,这是实际把我们的智能合约写入到Ropsten链的请求。和 eth_getTransactionByHash,这是一个读取交易的哈希值的请求(发送交易时的一个典型模式)。要了解更多关于发送交易的信息,请查看这个使用Web3发送交易的教程。

本教程的第一部分就到此为止。 接下来还有第二部分,将通过铸造NFT与我们的智能合约进行交互,及第三部分,展示如何在以太坊钱包中查看你的NFT