Foundry搭建和使用
Foundry搭建和使用
Foundry介绍
Foundry 是一个智能合约开发工具链。
Foundry 管理您的依赖关系、编译项目、运行测试、部署,并允许您通过命令行和 Solidity 脚本与链交互。
要开始使用 Foundry,请安装 Foundry 并设置第一个项目。
本节将向您概述如何创建和使用现有项目。
本节概述将为您提供有关如何使用“forge”来开发、测试和部署智能合约所需的所有知识。
了解如何使用“cast”与智能合约交互、发送交易以及从命令行获取链上数据。
了解 anvil
, Foundry 的本地节点。
了解如何使用 chisel
- Foundry 集成的 Solidity REPL。
Foundry 配置
Foundry 配置指引:
教程
与 Foundry 建立智能合约的教程。
- 使用 Solmate 创建 NFT
- Docker 和 Foundry
- 测试 EIP-712 签名
- Solidity 脚本
- 使用 Cast 和 Anvil 分叉(Fork)主网
- 学习 Foundry 视频
附录
参考手册, 疑难解答等等
- FAQ
- CLI 参考
- forge 命令
- cast 命令
- anvil 命令
- chisel 命令
- Config 参考
- Cheatcodes 参考
- Forge 标准库 参考
- DSTest 参考
- Miscellaneous
Foundry安装
如果在安装过程中遇到任何问题,请查看 常见问题解答 。
预编译二进制文件
可以从 GitHub 发布页面获取预编译的二进制文件。 最好使用 Foundryup 来更好地管理这些文件。
使用 Foundryup
Foundryup 是 Foundry 工具链安装程序。您可以在 这里找到更多信息。
打开终端并运行以下命令:
1 | curl -L https://foundry.paradigm.xyz | bash |
这将安装 Foundryup,然后只需按照屏幕上的说明操作,即可在 CLI 中使用 foundryup
命令。
仅运行 foundryup
将安装最新的(夜间) 预编译二进制文件 :forge
、cast
、anvil
和 chisel
。 使用 foundryup --help
获取更多选项,例如从特定版本或提交安装。
从源代码构建
先决条件
您将需要 Rust 编译器和 Cargo,Rust 包管理器。 安装两者的最简单方法是使用 rustup.rs
。
Foundry 通常仅支持在最新的稳定 Rust 版本上构建。 如果您使用较旧的 Rust 版本,可以使用 rustup
进行更新:
1 | rustup update stable |
在 Windows 上,您还需要安装带有 “使用 C++进行桌面开发” 工作负载选项的最新版本的 Visual Studio。
构建
您可以使用不同的 Foundryup 标志:
1 | foundryup --branch master |
或者,使用单个 Cargo 命令:
1 | cargo install --git https://github.com/foundry-rs/foundry --profile local --locked forge cast chisel anvil |
或者,通过手动从 Foundry 存储库的本地副本构建:
1 | # clone the repository |
使用 Docker 使用 Foundry
Foundry 也可以完全在 Docker 容器中使用。如果您没有安装 Docker,可以直接从 Docker 网站安装。
安装后,可以通过运行以下命令下载最新版本:
1 | docker pull ghcr.io/foundry-rs/foundry:latest |
也可以在本地构建 docker 镜像。从 Foundry 存储库运行:
1 | docker build -t foundry . |
对 Foundry 项目进行容器化
本教程向您展示如何使用 Foundry 的 Docker 镜像构建、测试和部署智能合约。 它改编自 solmate nft 教程中的代码。 如果您还没有完成该教程,并且是 solidity 的新手,您可能想先从它开始。 或者,如果您对 Docker 和 Solidity 有一定的了解,您可以使用自己现有的项目并进行相应的调整。 此处 提供了 NFT 和 Docker 内容的完整源代码。
本教程仅用于说明目的,并按原样提供。 本教程未经审核或全面测试。 不应在生产环境中使用本教程中的任何代码。
安装和设置
运行本教程所需的唯一安装是 Docker,以及您选择的 IDE(可选)。 按照 Docker 安装说明。
为了使以后的命令简洁明了,让我们重新标记镜像(image): docker tag ghcr.io/foundry-rs/foundry:latest foundry:latest
在本地安装 Foundry 并不是严格要求的,但它可能有助于调试。 您可以使用 foundryup 安装它。
最后,要使用本教程的任何 cast
或 forge create
部分,您需要访问以太坊节点。 如果您没有自己的节点在运行(可能),您可以使用第三方节点服务。 我们不会在本教程中推荐特定的提供商。 开始学习节点即服务的好地方是 Ethereum 的文章 主题。
对于本教程的其余部分,假设您的以太坊节点的 RPC 端点设置如下:export RPC_URL=<YOUR_RPC_URL>
Foundry docker 镜像导览
docker 镜像可以通过两种主要方式使用:
- 作为接口直接使用 forge 和 cast
- 作为构建您自己的容器化测试、构建和部署工具的基础镜像
我们将涵盖两者,但让我们先看看使用 docker 与 foundry 的接口。 这也是一个很好的测试,表明您的本地安装工作正常!
我们可以针对我们的 docker 镜像运行任何 cast
命令。 让我们获取最新的区块信息:
1 | $ docker run foundry "cast block --rpc-url $RPC_URL latest" |
如果我们在一个包含一些 Solidity 源代码 的目录中,我们可以将该目录挂载到 docker 中,并根据需要使用 forge
。 例如:
1 | $ docker run -v $PWD:/app foundry "forge test --root /app --watch" |
您可以看到我们的代码完全在容器内编译和测试。 此外,由于我们传递了 --watch
选项,容器将在检测到更改时重新编译代码。
注意:Foundry docker 镜像基于 alpine 构建,并设计为尽可能轻量化。 因此,它目前不包括像
git
这样的开发资源。 如果您计划在容器内管理整个开发生命周期,您应该在 Foundry 的镜像之上构建自定义开发镜像。
创建一个 “构建和测试” 镜像
让我们使用 Foundry 的 docker 镜像作为使用我们自己的 Docker 镜像的基础。 我们将使用镜像来:
- 构建我们的 solidity 代码
- 运行我们的可靠性测试
一个简单的 Dockerfile
可以实现这两个目标:
1 | # Use the latest foundry image |
您可以构建此 docker 镜像并观察 forge 在容器内构建/运行测试:
1 | $ docker build --no-cache --progress=plain 。 |
现在,如果我们的一个测试失败了怎么办? 随意修改 src/test/NFT.t.sol
使其中一个测试失败。 再次尝试构建镜像。
1 | $ docker build --no-cache --progress=plain . |
我们的镜像未能建立,因为我们的测试失败了! 这实际上是一个很好的属性,因为这意味着如果我们有一个成功构建的 Docker 镜像(因此可以使用),我们就知道镜像中的代码通过了测试。*
*当然,docker 镜像的监管链非常重要。 Docker 层哈希对于验证非常有用。 在生产环境中,考虑[签署你的 docker 镜像](https://docs.docker.com/engine/security/trust/#:%7E:text=To%20sign%20a%20Docker%20Image,the%20local%20Docker%20trust%20repository)。
创建部署镜像
现在,我们将继续讨论更高级的 Dockerfile。 让我们添加一个入口点,允许我们使用构建(和测试!)的镜像来部署我们的代码。 我们可以首先针对 Rinkeby 测试网。
1 | # Use the latest foundry image |
让我们构建镜像,这次给它命名:
1 | $ docker build --no-cache --progress=plain -t nft-deployer . |
以下是我们如何使用我们的 docker 镜像进行部署:
1 | $ docker run nft-deployer --rpc-url $RPC_URL --constructor-args "ForgeNFT" "FNFT" "https://ethereum.org" --private-key $PRIVATE_KEY ./src/NFT.sol:NFT |
我们刚刚在 docker 容器中完全构建、测试和部署了我们的合约! 本教程旨在用于测试网,但您可以针对主网运行完全相同的 Docker 镜像,并确信相同的代码正在由相同的工具部署。
为什么这有用?
Docker 是关于可移植性、可复制性和环境不变性的。 这意味着当您在环境、网络、开发人员等之间切换时,您可以减少对意外变化的关注。以下是一些基本示例,说明为什么我喜欢使用 Docker 镜像进行智能合约部署:
- 减少确保系统级依赖项在部署环境之间匹配的开销(例如,您的生产运行器是否始终具有与您的开发运行器相同版本的
forge
?) - 增加代码在部署之前已经过测试并且没有被更改的信心(例如,如果在上面的镜像中,您的代码在部署时重新编译,这是一个主要的危险信号)。
- 缓解职责分离的痛点:拥有主网凭证的人无需确保他们拥有最新的编译器、代码库等。很容易确保某人在测试网中运行的 docker 部署映像与针对主网的相同。
- 冒着听起来像 web2 的风险,Docker 是几乎所有公共云提供商的公认标准。 它可以轻松安排需要与区块链交互的作业、任务等。
故障排除
如上所述,默认情况下,Foundry 镜像不包含 git
。 这可能会导致某些命令在没有明确原因的情况下失败。 例如:
1 | $ docker run foundry "forge init --no-git /test" |
在这种情况下,失败仍然是由于缺少 git
安装造成的。 建议的修复方法是构建现有的 Foundry 镜像并安装您需要的任何其他开发依赖项。
创建一个新项目
要使用 Foundry 启动一个新项目,请使用 forge init
:
1 | $ forge init hello_foundry |
这将从默认模板创建一个新目录 hello_foundry
。 这也会初始化一个新的 git
存储库。
如果你想使用不同的模板创建一个新项目,你可以传递 --template
指令,如下所示:
1 | $ forge init --template https://github.com/foundry-rs/forge-template hello_template |
现在,让我们检查一下默认模板的样子:
1 | $ cd hello_foundry |
默认模板安装了一个依赖项:Forge 标准库。 这是用于 Foundry 项目的首选测试库。 此外,该模板还附带一个空的入门合约和一个简单的测试。
让我们构建项目:
1 | $ forge build |
并运行测试:
1 | $ forge test |
您会注意到产生了两个新目录:out
和 cache
。
out
目录包含您的合约工件(artifact,例如 ABI,而 cache
目录被 forge
使用来(记录),以便仅仅去重新编译那些必要编译的内容。
💡 提示
您始终可以通过在末尾添加
--help
来打印任何子命令(或它们的子命令)的帮助。
你可以观看 这些初学者教程,如果你是一个视频学习者
在现有项目工作
如果您下载一个使用 Foundry 的现有项目,那真的很容易上手。
对于这个例子,我们将使用PaulRBerg的foundry-template
。
首先,克隆该项目并在项目目录中运行 forge install
。
1 | $ git clone https://github.com/PaulRBerg/foundry-template |
我们运行 forge install
来安装项目中的子模块依赖项。
要构建,请使用 forge build
:
1 | $ forge build |
要进行测试,请使用 forge test
:
1 | $ forge test |
依赖
默认情况下,Forge 使用 git submodules 管理依赖项,这意味着它可以与任何包含智能合约的 GitHub 代码库一起使用。
添加依赖
要添加依赖项,请运行 forge install
:
1 | $ forge install transmissions11/solmate |
这将拉取 solmate
库,在 git 中暂存 .gitmodules
文件并使用消息“Installed solmate”进行提交。
如果我们现在检查 lib
文件夹:
1 | $ tree lib -L 1 |
我们可以看到Forge安装了solmate
!
默认情况下,forge install
安装最新的 master 分支版本。 如果你想安装一个特定的标签或提交,你可以这样做:
1 | $ forge install transmission11/solmate@v7 |
重新映射依赖项
Forge 可以重新映射(remap)依赖关系,使它们更容易导入。 Forge 将自动尝试为您推断出一些重新映射:
1 | $ forge remappings |
这些重新映射意味着:
- 要从
forge-std
导入,我们会这样写:import "forge-std/Contract.sol";
- 要从
ds-test
导入,我们会这样写:import "ds-test/Contract.sol";
- 要从
solmate
导入,我们会这样写:import "solmate/Contract.sol";
- 要从
weird-erc20
导入,我们会这样写:import "weird-erc20/Contract.sol";
您可以通过在项目的根目录中创建一个 remappings.txt
文件来自定义这些重新映射。
让我们创建一个名为 solmate-utils
的重映射,它指向 solmate repo中的 utils
文件夹!
1 | solmate-utils/=lib/solmate/src/utils/ |
您还可以在 foundry.toml
中设置重映射。
1 | remappings = [ |
现在我们可以像这样导入 solmate repo的 src/utils
中的任何合约:
1 | import "solmate-utils/LibString.sol"; |
更新依赖
您可以使用 forge update
将特定依赖项更新为您指定版本的最新提交。 例如,如果我们想从我们之前安装的 solmate
主版本中提取最新的提交,我们将运行:
1 | $ forge update lib/solmate |
或者,您可以通过运行 forge update
一次对所有依赖项执行更新。
删除依赖
您可以使用 forge remove ...
删除依赖项,其中 <deps>
是依赖项的完整路径或只是名称 . 例如,要删除 solmate
,这两个命令是等价的:
1 | $ forge remove solmate |
与 Hardhat 兼容
Forge 还支持基于 Hardhat 的项目,其中依赖项是 npm 包(存储在 node_modules
中)并且其合约存储在 contracts
中而不是 src
中。
要启用 Hardhat 兼容模式,请传递 --hh
标志。
项目布局
Forge 在构建项目的方式上是灵活的。 默认情况下,Forge 项目结构为:
1 | . |
- 您可以使用
foundry.toml
配置 Foundry 的行为。 - 重新映射在
remappings.txt
中指定。 - 合约的默认目录是
src/
。 - 测试的默认目录是
test/
,其中任何具有以test
开头的函数的合约都被视为测试。 - 依赖项作为 git 子模块存储在
lib/
中。
您可以分别使用 --lib-paths
和 --contracts
标志配置 Forge 在何处查找依赖项和合约。 或者,您可以在 foundry.toml 中配置它。
结合重新映射,这为您提供了支持其他工具链(例如 Hardhat 和 Truffle)的项目结构所需的灵活性。
对于获得自动 Hardhat 支持,您还可以传递 --hh
标志,它设置以下标志:--lib-paths node_modules --contracts contracts
。