首先让我们做一点清理工作。
我们想删除一些自动生成的但是不太需要的代码。我们要自己编写。
首先看一下目录结构:
先删除 test 文件夹下的 sample-test.js
文件。
然后删除 scripts
目录下的 sample-script.js
文件,
最后再删除 contracts
目录下的 Greeter.sol
。
注意,只是删除文件,不要删除这些文件所在的文件夹!
现在,在 VSCode 中打开项目,让我们开始编写 NFT 合约。如果您从未编写过智能合约,请不要担心。跟着我们的教程走。如果还有不明白的可以谷歌或者在留言板提问。
在contracts
目录下,创建一个文件命名为:MyEpicNFT.sol
。在使用 Hardhat 时文件结构非常重要,所以在这里要小心!
注意:建议大家下载VSCode 的 Solidity扩展,它提供了很好的语法突出显示。
这里我们从一份非常基本的合约开始,从浅入深。
// SPDX-License-Identifier: UNLICENSED
pragma solidity ^0.8.1;
import "hardhat/console.sol";
contract MyEpicNFT {
constructor() {
console.log("This is my NFT contract. Whoa!");
}
}
注意:有时 VSCode 本身会抛出不真实的错误,例如,它可能会在 hardhat 导入下划线并说它不存在。这些可能是因为您的全局 Solidity 编译器未在本地设置。如果您不知道如何解决此问题,可以暂时忽略这些。另外我建议你不要使用 VSCode 的终端,使用你自己单独的终端!如果未设置编译器,有时 VSCode 终端会出现问题。
让我们在这里逐行进行解释说明:
// SPDX-License-Identifier: UNLICENSED
只是一个注释。它被称为“SPDX 许可证标识符”,您可以在此处阅读更多相关信息。
pragma solidity ^0.8.1;
这是我们希望合约使用的 Solidity 编译器的版本。它意思是:“在运行这个程序时,我只想使用版本为 0.8.1 或更高版本但不高于 0.9.0 的 Solidity 编译器。注意,请确保在 hardhat.config.js
中相应地设置了编译器(例如0.8.1)。
import "hardhat/console.sol";
Hardhat 可以让我们能够在合约中执行一些控制台日志。调试智能合约实际上很有挑战性,这是 Hardhat 为我们提供的相对容易的方式之一。
contract MyEpicNFT {
constructor() {
console.log("This is my NFT contract. Whoa!");
}
}
智能合约有点像其他语言中的 class
。如果我们第一次初始化这个合约,那个构造函数就会运行并打印出这一行。你也可、可以修改打印的这一行,改成你想打印的其他内容。
现在我们有了一个智能合约!但是,我们不知道它是否有效。我们实际上需要:
我们将编写一个自定义脚本来为我们处理这 3 个步骤。
进入 scripts
目录并创建一个名为 run.js
的文件。
这是 run.js
里面的内容:
const main = async () => {
const nftContractFactory = await hre.ethers.getContractFactory('MyEpicNFT');
const nftContract = await nftContractFactory.deploy();
await nftContract.deployed();
console.log("Contract deployed to:", nftContract.address);
};
const runMain = async () => {
try {
await main();
process.exit(0);
} catch (error) {
console.log(error);
process.exit(1);
}
};
runMain();
注意:VSCode 可能会自动导入以太币。我们不需要导入以太。
我们先来逐行解释一下上面的代码。
const nftContractFactory = await hre.ethers.getContractFactory("MyEpicNFT");
这实际上将编译我们的合约并在目录下生成我们使用合约所需的必要文件目录 artifacts
。运行后去检查一下。
const nftContract = await nftContractFactory.deploy();
这里发生的是,Hardhat 将为我们创建一个本地以太坊网络,但只是为了这个合约。然后,在脚本完成后,它将销毁该本地网络。所以,每次你运行合约时,它都会是一个全新的区块链。重点是什么?这有点像每次都刷新你的本地服务器,所以总是从头开始,这样就很容易调试错误。
await nftContract.deployed();
我们将等到我们的合约被正式挖掘并部署到我们的本地区块链!hardhat实际上在你的机器上创建了假“矿工”,以尽力模仿实际的区块链。
我们的构造函数constructor
在实际完全部署时运行!
console.log("Contract deployed to:", nftContract.address);
最后,一旦部署完成,就会给我们部署合约的地址 nftContract.address
。这个地址是我们在区块链上真正找到合约的方式。只不过现在在我们的本地区块链上,只有我们。
但是,实际区块链上有数百万份合约。所以,这个地址让我们可以轻松访问我们感兴趣的合约!在后面的几节课中,当我们将合约部署到实际的区块链时,这就可以派上用场了。
在运行此功能之前,请确保将 hardhat.config.js
中的 solidity: “0.8.4” 更改为 solidity: “0.8.1”。
让我们运行它!打开你的终端并运行:
npx hardhat run scripts/run.js
你可以看到合约中运行的 console.log
,打印出来的合约地址!!!这是我得到的:
在这些代码块中,您会注意到我们经常的使用hre.ethers
,但hre
从未在任何地方导入?那么为什么可以使用呢?
直接去看 Hardhat 文档,您会注意到这一点:
Hardhat Runtime Environment,或简称 HRE,是一个包含 Hardhat 在运行任务、测试或脚本时公开的所有功能的对象。实际上,Hardhat 就是 HRE。
那么这是什么意思?好吧,每次你运行一个以 npx hardhat
开头的终端命令时,你都是用代码中指定的hardhat.config.js
态构建这个hre
对象!这意味着您将永远不必实际对文件进行某种导入,例如:
const hardhat = require("hardhat")