部署智能合约并与之交互 - OpenZeppelin 文档

本文介绍了如何在以太坊网络上部署和交互智能合约。首先,文章讲解了如何设置本地区块链环境,然后演示了如何使用 Hardhat 部署智能合约。接着,文章展示了如何通过 Hardhat console 和 JavaScript 代码与已部署的合约进行交互,包括发送交易和查询状态。最后,文章说明了下一步学习的方向,包括自动化测试、连接公共测试网络以及为主网做准备。

部署和交互智能合约

与大多数软件不同,智能合约不是在你的计算机或某人的服务器上运行:它们存在于以太坊网络本身。这意味着与它们的交互与更传统的应用程序略有不同。

本指南将涵盖你开始使用合约所需了解的一切,包括:

设置本地区块链

在我们开始之前,我们首先需要一个可以部署合约的环境。以太坊区块链(通常被称为“主网”,即“主网络”)需要花费真金白银才能使用它,以 Ether(其原生货币)的形式。这使得它在尝试新想法或工具时成为一个糟糕的选择。

为了解决这个问题,存在许多“测试网”(即“测试网络”):这些包括 Sepolia 和 Holesky 区块链。它们的工作方式与主网非常相似,但有一个区别:你可以免费获得这些网络的 Ether,因此使用它们不需要你花费一分钱。但是,你仍然需要处理私钥管理、12 秒或更长的区块时间和实际获取这些免费的 Ether。

在开发过程中,最好使用本地区块链。它在你的机器上运行,不需要互联网访问,为你提供所需的所有 Ether,并立即挖掘区块。这些原因也使本地区块链非常适合自动化测试

如果你想学习如何在公共区块链(如以太坊测试网)上部署和使用合约,请前往我们的连接到公共测试网络指南。

Hardhat 自带一个内置的本地区块链,即 Hardhat Network

启动后,Hardhat Network 将创建一组未锁定的账户并为其提供 Ether。

$ npx hardhat node

Hardhat Network 将打印出其地址 http://127.0.0.1:8545,以及可用账户列表及其私钥。

请记住,每次运行 Hardhat Network 时,它都会创建一个全新的本地区块链——保留先抢跑的状态。这对于短期的实验来说是可以的,但这意味着你需要打开一个窗口运行 Hardhat Network 才能完成这些指南。

当未指定网络且未配置默认网络或默认网络设置为 hardhat 时,Hardhat 将始终启动 Hardhat Network 的实例。
你也可以在_开发模式_下运行一个实际的以太坊节点。这些节点的设置稍微复杂一些,并且在测试和开发方面不如前者灵活,但更能代表真实网络。

部署智能合约

开发智能合约指南中,我们设置了我们的开发环境。

如果你还没有完成此设置,请创建设置项目,然后创建编译我们的 Box 智能合约。

在完成项目设置后,我们现在可以部署合约了。我们将部署来自开发智能合约指南的 Box。请确保你在 contracts/Box.sol 中有一个 Box 的副本。

Hardhat 使用声明式部署脚本来部署合约。

我们将创建一个脚本来部署我们的 Box 合约。我们将此文件另存为 scripts/deploy.js

// scripts/deploy.js
async function main () {
  // We get the contract to deploy
  // 我们获取要部署的合约
  const Box = await ethers.getContractFactory('Box');
  console.log('Deploying Box...');
  // 部署 Box...
  const box = await Box.deploy();
  await box.waitForDeployment();
  console.log('Box deployed to:', await box.getAddress());
  // Box 部署到:
}

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

我们在脚本中使用 ethers,因此我们需要安装它和 @nomicfoundation/hardhat-ethers 插件

$ npm install --save-dev @nomicfoundation/hardhat-ethers ethers

我们需要在配置中添加我们正在使用 @nomicfoundation/hardhat-ethers 插件。

// hardhat.config.js
require("@nomicfoundation/hardhat-ethers");

...
module.exports = {
...
};

使用 run 命令,我们可以将 Box 合约部署到本地网络(Hardhat Network):

$ npx hardhat run --network localhost scripts/deploy.js
Deploying Box...
// 部署 Box...
Box deployed to: 0x5FbDB2315678afecb367f032d93F642f64180aa3
// Box 部署到:0x5FbDB2315678afecb367f032d93F642f64180aa3
Hardhat 不会跟踪你已部署的合约。我们在脚本中显示了已部署的地址(在我们的示例中为 0x5FbDB2315678afecb367f032d93F642f64180aa3)。这在以编程方式与它们交互时非常有用。

全部完成!在真实网络上,此过程将花费几秒钟,但在本地区块链上几乎是瞬间完成的。

如果你遇到连接错误,请确保你在另一个终端中运行本地区块链
请记住,本地区块链不会在多次运行中保持其状态!如果你关闭本地区块链进程,则必须重新部署你的合约。

从控制台交互

在我们部署Box 合约后,我们可以立即开始使用它。

我们将使用 Hardhat 控制台与我们在 localhost 网络上部署的 Box 合约进行交互。

我们需要指定我们在部署脚本中显示的 Box 合约的地址。
重要的是,我们显式地设置 Hardhat 连接到我们的控制台会话的网络。如果我们不这样做,Hardhat 将默认使用一个新的临时网络,我们的 Box 合约不会部署到该网络。
$ npx hardhat console --network localhost
Welcome to Node.js v20.17.0.
Type ".help" for more information.
> const Box = await ethers.getContractFactory('Box');
undefined
> const box = Box.attach('0x5FbDB2315678afecb367f032d93F642f64180aa3')
undefined

发送交易

Box 的第一个函数 store 接收一个整数值并将其存储在合约存储中。由于此函数修改区块链状态,我们需要发送交易到合约才能执行它。

我们将发送一个交易来调用带有数值的 store 函数:

> await box.store(42)
{
  hash: '0x3d86c5c2c8a9f31bedb5859efa22d2d39a5ea049255628727207bc2856cce0d3',
...

查询状态

Box 的另一个函数称为 retrieve,它返回存储在合约中的整数值。这是区块链状态的查询,因此我们不需要发送交易:

> await box.retrieve()
42n

由于查询仅读取状态而不发送交易,因此没有交易哈希要报告。这也意味着使用查询不花费任何 Ether,并且可以在任何网络上免费使用。

我们的 Box 合约返回 uint256,对于 JavaScript 来说,这是一个太大的数字,因此我们返回了一个大数字对象。我们可以使用 (await box.retrieve()).toString() 将大数字显示为字符串。
> (await box.retrieve()).toString()
'42'
要了解有关使用控制台的更多信息,请查看 Hardhat 文档

以编程方式交互

控制台对于原型设计和运行一次性查询或交易非常有用。但是,最终你需要从你自己的代码中与你的合约进行交互。

在本节中,我们将了解如何从 JavaScript 与我们的合约进行交互,并使用 Hardhat 运行我们的脚本以及我们的 Hardhat 配置。

请记住,还有许多其他可用的 JavaScript 库,你可以选择最喜欢的任何一个。一旦合约部署完毕,你就可以通过任何库与它进行交互!

设置

让我们从一个新的 scripts/index.js 文件开始编码,我们将在其中编写我们的 JavaScript 代码,首先是一些样板代码,包括用于编写异步代码

// scripts/index.js
async function main () {
  // Our code will go here
  // 我们的代码将放在这里
}

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

我们可以通过询问本地节点一些内容来测试我们的设置,例如启用账户的列表:

// Retrieve accounts from the local node
// 从本地节点检索账户
const accounts = (await ethers.getSigners()).map(signer => signer.address);
console.log(accounts);
我们不会在每个代码段上重复此样板代码,但请确保始终在上面定义的 main 函数内部编写代码!

使用 hardhat run 运行上面的代码,并检查你是否收到响应中可用账户的列表。

$ npx hardhat run --network localhost ./scripts/index.js
[\
  '0xf39Fd6e51aad88F6F4ce6aB8827279cffFb92266',\
  '0x70997970C51812dc3A010C7d01b50e0d17dc79C8',\
...\
]

这些账户应该与你之前启动本地区块链时显示的账户匹配。现在我们有了第一个从区块链中获取数据的代码段,让我们开始使用我们的合约。请记住,我们将代码添加到上面定义的 main 函数内部

获取合约实例

为了与我们部署的 Box 合约进行交互,我们将使用 ethers 合约实例

ethers 合约实例是一个 JavaScript 对象,表示我们在区块链上的合约,我们可以使用它与我们的合约进行交互。为了将其附加到我们已部署的合约,我们需要提供合约地址。

// Set up an ethers contract, representing our deployed Box instance
// 设置一个 ethers 合约,代表我们部署的 Box 实例
const address = '0x5FbDB2315678afecb367f032d93F642f64180aa3';
const Box = await ethers.getContractFactory('Box');
const box = Box.attach(address);
确保将 address 替换为你在部署合约时获得的地址,该地址可能与此处显示的地址不同。

我们现在可以使用此 JavaScript 对象与我们的合约进行交互。

调用合约

让我们首先显示 Box 合约的当前值。

我们需要调用合约的只读 retrieve() 公共方法,并等待响应:

// Call the retrieve() function of the deployed Box contract
// 调用已部署 Box 合约的 retrieve() 函数
const value = await box.retrieve();
console.log('Box value is', value.toString());
// Box 值为

此代码段等效于我们之前从控制台运行的查询。现在,通过再次运行该脚本并检查打印的值来确保一切顺利运行:

$ npx hardhat run --network localhost ./scripts/index.js
Box value is 42
// Box 值为 42
如果你在任何时候重新启动了你的本地区块链,此脚本可能会失败。重新启动会清除所有本地区块链状态,因此 Box 合约实例将不会位于预期的地址。 <br>如果发生这种情况,只需启动本地区块链重新部署Box 合约。

发送交易

我们现在将发送一个交易到 store 以在我们的 Box 中存储一个新值。

让我们在我们的 Box 中存储一个值为 23,然后使用我们之前编写的代码来显示更新后的值:

// Send a transaction to store() a new value in the Box
// 发送一个交易到 store() 以在 Box 中存储一个新值
await box.store(23);

// Call the retrieve() function of the deployed Box contract
// 调用已部署 Box 合约的 retrieve() 函数
const value = await box.retrieve();
console.log('Box value is', value.toString());
// Box 值为
在实际应用中,你可能想要估算你交易的 gas,并检查 gas 价格预言机以了解在每笔交易中使用的最佳值。

我们现在可以运行该代码段,并检查 Box 的值是否已更新!

$ npx hardhat run --network localhost ./scripts/index.js
Box value is 23
// Box 值为 23

下一步

既然你知道如何设置本地区块链、部署合约以及手动和以编程方式与它们进行交互,你将需要了解有关测试环境、公共测试网络和投入生产的更多信息:

← 开发智能合约

编写自动化测试 →

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

0 条评论

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