本文介绍了如何使用Foundry进行智能合约开发,包括环境设置、合约编写、测试和部署。Foundry是一个全面的工具套件,适用于以太坊区块链上的去中心化应用开发。
重要通知
本指南包含对 Goerli 测试网的引用,该测试网已不再积极维护。虽然与此链相关的具体步骤可能不再适用,但整体流程可能对其他链仍然有效。我们建议为你的实现探索当前的替代方案。如果你希望看到本指南的更新版本,请告诉我们!
Foundry 是一个智能合约开发工具包,提供了一套全面的工具,用于在以太坊区块链上构建和部署去中心化应用程序(dApps)。它旨在帮助从初学者到高级开发者的所有开发者创建安全高效的智能合约。本指南旨在深入理解 Foundry、其功能以及如何使用它进行智能合约开发。
你需要准备的内容
你将要做的事情
Foundry 是一套全面的工具,用于在以太坊区块链上构建和部署去中心化应用程序(dApps)。它旨在让所有级别的开发者更容易创建和部署安全高效的智能合约。使用 Foundry,你可以使用 Solidity 编程语言编写智能合约,编译它,将其部署到以太坊区块链,并与之交互。
Foundry 提供了一个命令行界面(CLI),使得创建、部署和管理智能合约变得容易。CLI 提供了一组命令,你可以使用这些命令执行与智能合约开发相关的各种任务,例如创建新项目、编写合约、编译合约、部署合约以及与合约交互。
当你创建一个新的 Foundry 项目时,你可以使用 Solidity 编程语言编写智能合约。编写完合约后,你可以使用 Foundry CLI 编译它。编译器将生成 ABI(应用程序二进制接口)和字节码,这些可以用于将合约部署到以太坊区块链。要了解更多关于 ABI 的信息,请查看此 QuickNode 指南。
编译完合约后,你可以使用 Foundry CLI 将其部署到以太坊区块链。部署完成后,你可以使用 Foundry CLI 或 web3.js 库与合约交互。
Foundry 在几个方面与其他智能合约开发框架(如 Hardhat、Ganache 和 Remix.IDE)不同:
Foundry 提供了工具和功能,可以轻松地在以太坊和其他 EVM 兼容的区块链(如 Polygon、Arbitrum、Optimism、Avalanche)上构建和部署你的 dApps。
下一节将介绍如何设置我们的开发环境,以便使用 Foundry 和 QuickNode 创建和部署智能合约。
你需要一个 API 端点来与以太坊区块链通信。欢迎你使用公共节点或部署和管理你自己的基础设施;但是,如果你希望获得 8 倍更快的响应时间,你可以将繁重的工作交给我们。在此注册一个免费账户。
登录后,点击创建端点并选择 以太坊 链和 Goerli 测试网络。
创建端点后,请妥善保管 HTTP 提供者 URL,因为你在部署和与部署的智能合约交互时需要它。
在本指南中,我们将使用 Torus Wallet,这是一个支持多条链和网络的非托管钱包,包括以太坊、Arbitrum、Polygon 和其他 EVM 相关链。你也可以使用任何其他非托管的 Web3 钱包(例如 MetaMask、Phantom),只要你可以访问你的私钥。
请记住,要在 Goerli 测试网络上部署,你需要拥有测试网 ETH 来支付交易费用。这些费用应该是最小的,不应超过 0.25 美元。你可以在 Multi-Chain QuickNode Faucet 获取测试 ETH。
要开始,请访问 Torus 并按照说明生成私钥。
在继续本指南的技术方面之前,请确保你的 Goerli 测试网络钱包地址上有足够的资金来支付合约部署和交互的费用。
在安装了 Node.js(版本 18 以上)后,让我们为智能合约开发设置一个项目文件夹:
mkdir foundry_project && cd foundry_project && npm init -y
然后在 foundry_project 中,让我们安装 Foundry。你可以使用 foundryup 安装最新版本,或从源代码构建(需要 rust 和 cargo)。在本教程中,我们将使用 foundryup 安装。
curl -L https://foundry.paradigm.xyz | bash
这将下载 foundryup。然后通过运行以下命令安装 Foundry:
foundryup
如果一切顺利,你现在将拥有四个可用的二进制文件:forge、cast、anvil 和 chisel。
如果你使用 macOS 并显示以下错误,你需要输入 brew install libusb 来安装所需的库
dyld[32719]: Library not loaded: /usr/local/opt/libusb/lib/libusb-1.0.0.dylib
安装配置完成后,使用以下命令初始化一个 Foundry 项目:
forge init counter_contract
然后,导航到 counter_contract 中,你的项目结构应如下所示:
.
├── lib
├── script
├── src
└── test
foundry.toml
在下一节中,我们将查看位于 src 中的 Counter.sol 文件,然后在本指南的后面部分部署它。
在 src 文件夹中,打开 Counter.sol 文件:
// SPDX-License-Identifier: UNLICENSED
pragma solidity ^0.8.13;
contract Counter {
uint256 public number;
function setNumber(uint256 newNumber) public {
number = newNumber;
}
function increment() public {
number++;
}
}
这个合约非常简单,只包含 1 个状态变量和 2 个公共函数。
number 变量定义为 uint256 类型(256 位无符号整数),并且可以通过 public 关键字在合约外部公开访问。公共函数 setNumber 设置 number 状态变量的值。它接受一个 uint256 类型的输入,名为 newNumber,并将其设置为 number 的新值。公共函数 increment 将 number 状态变量的值增加 1。
要编译合约,请在终端中运行以下 forge 命令:
forge build
你应该看到编译详细信息,例如:
[⠰] Compiling...
[⠘] Compiling 19 files with 0.8.15
[⠊] Solc 0.8.15 finished in 1.31s
Compiler run successful
在下一节中,你将学习如何在 Foundry 中运行测试。
打开 test/Counter.t.sol 文件:
// SPDX-License-Identifier: UNLICENSED
pragma solidity ^0.8.13;
import "forge-std/Test.sol";
import "../src/Counter.sol";
contract CounterTest is Test {
Counter public counter;
function setUp() public {
counter = new Counter();
counter.setNumber(0);
}
function testIncrement() public {
counter.increment();
assertEq(counter.number(), 1);
}
function testSetNumber(uint256 x) public {
counter.setNumber(x);
assertEq(counter.number(), x);
}
}
上面的代码对我们上一节创建的合约进行单元测试。让我们回顾一下代码。
导入
代码首先导入了两个文件:forge-std/Test.sol
和 ../src/Counter.sol
。第一个导入 forge-std/Test.sol
是用于编写测试的 Forge 标准库。第二个导入 ../src/Counter.sol
是被测试的主要智能合约。
合约定义
然后代码定义了一个名为 CounterTest
的智能合约,它是从导入的 forge-std/Test.sol
库中的 Test
子合约。
合约属性
合约有一个公共属性 counter
,它是 Counter
智能合约的一个实例。
setUp 函数
setUp
函数是 Forge 测试库中的一个特殊函数,在每个测试之前运行。在此函数中,创建了一个新的 Counter
智能合约实例,并将其 number
属性设置为 0。
testIncrement 函数
testIncrement
函数测试 Counter
智能合约的 increment
函数。它首先调用 increment
函数,然后使用 assertEq
函数检查 Counter
实例的 number
属性是否等于 1。如果 number
属性不等于 1,测试将失败。
testSetNumber 函数
testSetNumber
函数测试 Counter
智能合约的 setNumber
函数。它接受一个 uint256
输入 x
并使用 x
作为参数调用 setNumber
函数。然后使用 assertEq
函数检查 Counter
实例的 number
属性是否等于 x
。如果 number
属性不等于 x
,测试将失败。
然后要执行测试,请运行以下 forge 终端命令:
forge test
你应该看到类似于以下输出:
Running 2 tests for test/Counter.t.sol:CounterTest
[PASS] testIncrement() (gas: 28356)
[PASS] testSetNumber(uint256) (runs: 256, μ: 27253, ~: 28342)
Test result: ok. 2 passed; 0 failed; finished in 11.95ms
你还可以使用以下命令打印测试函数的气体报告:
forge test --gas-report
过程完成后,你将观察到两个新文件夹 out 和 cache 的出现。out 目录包含你的智能合约的工件,包括 ABI,而 Forge 使用 cache 文件夹仅重新编译必要的组件。
要将你的 Counter 合约部署到网络上,请运行以下 forge create 命令。
你需要将 QUICKNODE_HTTP_URL 替换为你的实际 QuickNode 端点。此外,将 YOUR_PRIVATE_KEY 占位符替换为你的实际私钥。
forge create --rpc-url QUICKNODE_HTTP_URL \
--private-key YOUR_PRIVATE_KEY \
src/Counter.sol:Counter
你应该看到类似于以下输出:
[⠆] Compiling...
No files changed, and compilation skipped
Deployer: 0x1851CC3b4996f9a75302C694485bf7437F3a4b7a
Deployed to: 0xEd1BaAaf5147aa060e3B590c5EdC17C846aa489E
Transaction hash: 0xa1cf5316ab326b43871874bfeb462a15a7d2913b799869c83faad117e2c39eb6
我们可以通过访问区块浏览器(如 Etherscan)来确认。
注意,你还可以使用 anvil 在本地测试网上部署合约。要启动本地测试网服务器,请运行命令:
anvil
启动后,Anvil 将为你提供一个本地 RPC 端点和你可以测试的账户。
现在让我们与刚刚部署的 Counter 智能合约进行交互。
Foundry 包括 cast,一个用于执行以太坊 RPC 调用的 CLI。
要使用 Counter 合约的 setNumber 函数进行写调用,请使用 cast send 命令:
cast send YOUR_CONTRACT_ADDRESS "setNumber(uint256)" 10 --rpc-url QUICKNODE_HTTP_URL --private-key YOUR_PRIVATE_KEY
在上面的 cast 命令中,我们使用 10 作为输入负载。
你将看到类似于以下结果:
blockHash 0x66977720a56444502112851d144d0abbc48551c3842e49be81b739118adf051b
blockNumber 8492170
contractAddress
cumulativeGasUsed 1210319
effectiveGasPrice 3002296853
gasUsed 43494
logs []
logsBloom 0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000
root
status 1
transactionHash 0x5c3d0178a24fe6593439743a021b407293622caf8a4649ca9b027a8d4944fe77
transactionIndex 5
type 2
要进行读调用以查看 number 变量的状态,请使用 cast call 命令:
cast call YOUR_CONTRACT_ADDRESS "number()" --rpc-url QUICKNODE_HTTP_URL
结果:
0x0000000000000000000000000000000000000000000000000000000000000064
上面的十六进制值转换为 100。你可以使用此终端命令进行验证:echo $((0x0000000000000000000000000000000000000000000000000000000000000064))
你现在拥有使用 Foundry 开发智能合约的技能!
你在使用 Foundry 做什么?我们很想看看你正在创建的内容!在 Discord 或 Twitter 上与我们分享你的应用程序。如果你对本指南有任何反馈或问题,我们很乐意听取你的意见!
- 原文链接: quicknode.com/guides/eth...
- 登链社区 AI 助手,为大家转译优秀英文文章,如有翻译不通的地方,还请包涵~
如果觉得我的文章对您有用,请随意打赏。你的支持将鼓励我继续创作!