Solidity语言 - 如何使用 Hardhat 在 Solidity 中创建智能合约工厂

  • QuickNode
  • 发布于 2024-10-26 18:55
  • 阅读 40

本文介绍了如何使用Solidity实现工厂合约模式。首先,读者需要具备一些Solidity基础知识。接着,通过具体步骤展示了如何创建工厂合约,使其能够生成多个Greeter合约实例,并详细讲解了相关函数及其功能。最后,读者可以在本地环境中与合约进行互动,巩固所学内容。

概述

你好,读者!今天我们将提升你的 Solidity 技能。我们将带你走过如何实现工厂合约模式的过程。如果你之前没有听说过这个术语,不用担心;到本指南结束时,一切都会向你解释清楚。

话虽如此,在继续之前,你需要一些准备。你应该对 Solidity 有一定了解,并且要有一个良好的本地开发环境。

前提条件:

  • Solidity 知识
  • 熟悉终端的使用
  • 一款文本编辑器

什么是工厂合约?

工厂合约是生成其他智能合约的智能合约。就像一个鞋子工厂生产符合一定标准的鞋子一样,工厂合约将确保它生成的所有智能合约遵循某些任意特征。这是一个常见的模式,许多(如果不是所有)大型去中心化应用程序都在使用。例如,如果你熟悉 Uniswap,他们就实现了这一模式。每当你与 Uniswap 池进行交互时,该池实际上是由 Uniswap 工厂合约生成的一个智能合约。

这个模式在很多方面都是有用的。一个原因是它允许你创建相同合约的多个实例,类似于编程中的类。定义一次,然后你可以在任何想要的地方创建该类的新实例。如果你愿意,你可以跟踪工厂已部署的所有合约。它甚至可以为你节省一定的 gas,因为你可以先部署工厂,然后使用它来部署其他智能合约。但够了,让我们深入了解工厂合约模式。

初始化项目

在本指南中,我们将在本地机器上使用 Solidity。我的个人最爱工具是 Hardhat。首先,按顺序运行以下命令。我们将创建一个文件夹,进入该文件夹,初始化一个 JavaScript 项目,安装 Hardhat,并创建一些样板代码。

mkdir factory-contract
cd factory-contract
npm init -y
npm install --save-dev hardhat
npx hardhat

运行最后一个命令 npx hardhat 后,你将被提示回答一些问题。

  1. What do you want to do? > Create a basic sample project

  2. Hardhat project root: > . (yes, just a single dot)

  3. Do you want to install this sample project's dependencies with npm (@nomiclabs/hardhat-waffle ethereum-waffle chai @nomiclabs/hardhat-ethers ethers)? > y

回答完所有这些问题后,你已经成功设置项目以开始工作。现在我们可以开始编写一些 Solidity 代码了!

编写合约

首先,让我们打开项目的 contracts 文件夹,查看 Greeter.sol

//SPDX-License-Identifier: Unlicense
pragma solidity ^0.8.0;

import "hardhat/console.sol";

contract Greeter {
    string private greeting;

    constructor(string memory _greeting) {
        console.log("Deploying a Greeter with greeting:", _greeting);
        greeting = _greeting;
    }

    function greet() public view returns (string memory) {
        return greeting;
    }

    function setGreeting(string memory _greeting) public {
        console.log("Changing greeting from '%s' to '%s'", greeting, _greeting);
        greeting = _greeting;
    }
}

在这里我将依靠你已有的 Solidity 知识。我不会逐行分析这个合约的功能。你应该知道,它有 3 个函数:一个在初始化时调用的构造函数,一个获取函数,以及一个设置函数。

这是我们将创建工厂的合约。我们希望能够部署多个 Greeter 合约,甚至从工厂调用这些 setter/getter 函数。

为了开始我们的工厂合约,创建一个新的文件 Factory.sol 在我们的 contracts 文件夹中。

在该文件中,可以写入以下代码:

//SPDX-License-Identifier: Unlicense
pragma solidity ^0.8.0;

import "./Greeter.sol";

contract Factory {
   Greeter[] public GreeterArray;

   function CreateNewGreeter(string memory _greeting) public {
     Greeter greeter = new Greeter(_greeting);
     GreeterArray.push(greeter);
   }

   function gfSetter(uint256 _greeterIndex, string memory _greeting) public {
     Greeter(address(GreeterArray[_greeterIndex])).setGreeting(_greeting);
   }

   function gfGetter(uint256 _greeterIndex) public view returns (string memory) {
    return Greeter(address(GreeterArray[_greeterIndex])).greet();
   }
}

这就是我们需要的所有代码,以拥有一个功能齐全的工厂合约。你可以看到,在处理 Solidity 想要我们声明的 SPDX 和 pragma 后,我们导入了 Hardhat 开始时提供的 Greeter 合约。这给予了我们的 Factory 合约的能力去了解 Greeter 合约的形状。

接下来是第一个变量:GreeterArrayGreeterArray 是一个公共的 Greeter 合约数组。公共变量将在此合约部署时自动由 Solidity 编译器为它们生成一个获取函数。这让我们可以通过这个数组随时抓取任何由该工厂部署的 Greeter 合约。

接下来是 CreateNewGreeter 函数。这同样是一个公共函数,这意味着任何人/任何事都可以调用它。该函数有一个类型为字符串的参数。你可以在函数中看到,我们使用 new 关键字创建一个全新的合约。由于 Greeter 合约的构造函数要求一个参数,我们将 _greeting 参数传递给新创建的 Greeter 合约。随后我们将新创建的合约推入我们的 GreeterArray ,以便后续查找。

最后,我们有了我们的 greeter 和 setter 函数。每一个都接受一个 uint256 数字,表示我们想要查找的合约的索引。这个代码块可能看起来有点奇怪,但当你考虑这段代码时:Greeter(address(GreeterArray[_greeterIndex])) 如同我们传入的索引所指定的 Greeter 合约。由于我们此时位于一个 Greeter 合约中,我们可以访问 greetsetGreeting 函数。

凭借你新获得的Factory合约知识,我们可以转到 scripts 文件夹进行一些工作。

创建一个新的文件 factory.js,并将以下代码粘贴进去。

// We require the Hardhat Runtime Environment explicitly here. This is optional
// but useful for running the script in a standalone fashion through `node <script>`.
//
// When running the script with `npx hardhat run <script>` you'll find the Hardhat
// Runtime Environment's members available in the global scope.
const hre = require("hardhat");

async function main() {
  // Hardhat always runs the compile task when running scripts with its command
  // line interface.
  //
  // If this script is run directly using `node` you may want to call compile
  // manually to make sure everything is compiled
  // await hre.run('compile');

  // We get the contract to deploy
  const Factory = await hre.ethers.getContractFactory("Factory");
  const factory = await Factory.deploy();

  await factory.deployed();

  console.log("factory deployed to:", factory.address);
}

// We recommend this pattern to be able to use async/await everywhere
// and properly handle errors.
main()
  .then(() => process.exit(0))
  .catch((error) => {
    console.error(error);
    process.exit(1);
  });

我们有一个 视频 更深入地讲解了 Hardhat 的工作原理,但你可以知道,这个脚本基本上是 Hardhat 部署合约到本地环境所需的 大多数 样板代码。

现在我们可以进入有趣的部分。部署我们的工厂合约,并在“链上”环境中与之交互。我把链上放在引号中,因为我们将只是在本地机器上模拟该环境。但是,如果你对测试网络或甚至主网络进行部署,原理依然相同。

与工厂交互

打开你的终端并运行下面的命令。

npx hardhat node

这将在你的控制台中创建一个模拟以太坊环境。请确保在后台保持此终端运行,同时我们运行所有其他命令!

接下来,我们希望使用我们早先编写的脚本将合约部署到这个测试节点。为此在另一个终端中运行以下命令:

npx hardhat run scripts/factory.js --network localhost

这将部署你的工厂合约并在终端中记录合约地址。

合约部署后,我们可以使用下面的命令打开 Hardhat 的控制台。

npx hardhat console --network localhost

这是一个模拟的 JavaScript 控制台,能够访问我们在另一个终端运行的节点。

我们需要进行一系列有序的步骤:

  1. 获取 Factory 合约接口进行交互

  2. 通过工厂部署一个 Greeter 合约。

  3. 通过工厂与新创建的 Greeter 合约进行交互。

我将给你一块代码,下面的代码块。你应该一行一行地在控制台中输入,每输入一行按下回车来运行代码。

> const Factory = await ethers.getContractAt('Factory', '0x5FbDB2315678afecb367f032d93F642f64180aa3')
> await Factory.CreateNewGreeter('hello!')
> await Factory.GreeterArray(0)
> await Factory.gfGetter(0)
// Returns: 'hello!'
> await Factory.gfSetter(0, 'Double Hello!')
> await Factory.gfGetter(0)
// Returns: 'Double Hello!'

逐行分析,我们可以分解如下:

1. 通过合约地址和合约名称抓取我们部署的 Factory 合约。

2. 使用工厂部署新 Greeter 合约。

3. 通过 Factory 合约的 GreeterArray 索引号列出新创建的 Greeter 合约地址。

4. 调用 Greeter 的获取函数。

5. 调用 Greeter 的设置函数。

6. 再次调用 Greeter 的获取函数,以确认设置成功。

运行完所有这些命令后,你应该对如何进一步扩展有一个很好的了解。你可以再次调用 CreateNewGreeter 函数,并为第一个索引、第二个索引等重复这一模式。

另一点需要注意的是,当你在另一个终端中输入命令时,你应该看到活动在其他终端中发生。每当你使用写入命令(CreateNewGreeter 和 gfSetter)时,它将有新的交易发生,而每当使用读取命令(GreeterArray 和 gfGetter)时,你应该看到 eth_call/eth_chainId 的命令。

结论

恭喜你走到最后!你已经确实提升了你的 Solidity 技能,并且在通往与在场的最佳 Solidity 开发者合作的路上。 在本指南中,你了解了工厂合约的方法,以及如何在本地测试环境中实现你自己的工厂合约!

订阅我们的 新闻通讯 获取更多关于以太坊的文章和指南。如果你有任何反馈,请随时通过 Twitter 联系我们。你也可以在我们的 Discord 社区服务器与我们聊天,那里有一些你见过的最酷的开发者 :)

  • 原文链接: quicknode.com/guides/eth...
  • 登链社区 AI 助手,为大家转译优秀英文文章,如有翻译不通的地方,还请包涵~
点赞 0
收藏 0
分享
本文参与登链社区写作激励计划 ,好文好收益,欢迎正在阅读的你也加入。

0 条评论

请先 登录 后评论
QuickNode
QuickNode
江湖只有他的大名,没有他的介绍。