前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >使用 Foundry 开发环境

使用 Foundry 开发环境

作者头像
Tiny熊
发布2022-11-07 10:00:47
1.1K0
发布2022-11-07 10:00:47
举报
文章被收录于专栏:深入浅出区块链技术

本文作者:Tiny 熊[1]

Foundry 是一个全新的 EVM 开发环境。有了 Solidity-native 测试能力(使用原生的 Solidity 编写测试),强大的命令行工具和高性能的 Rust 工具,Foundry 更值得大家学习,翻译一篇 Foundry 的使用指南文章。

安装

官方安装指南可以在这里[2]找到。不过我自己在用foundryup获得anvil时遇到了麻烦,所以如果你想在 bash/zsh shell 上从源码构建,请使用以下方法。注意你需要先安装有gitcargo才能进行源代码构建。

代码语言:javascript
复制
git clone https://github.com/foundry-rs/foundry && \
    cd foundry && \
    cargo install --path ./cli --bins --locked --force && \
    cargo install --path ./anvil --locked --force

如果你选择了从源码构建,那么就需要花费给你一些精力,编译器有很多事情要做。

Foundry 包含的组件

Foundry 由三个不同的命令行工具(CLI)组成,包括forgecast,和anvil。首先,我们先了解下这些工具,然后用他们来构建和测试一个智能合约。

Cast

Cast 是一个 CLI 工具,用于对兼容以太坊虚拟机(EVM)的区块链进行 RPC 调用。使用cast,我们可以进行合约调用,查询数据,并处理编码和解码。cast有很多的子命令,所以要想获得完整的参考,请看 Foundry 书中的cast[3]一节!

要执行合约调用而不发布交易,我们可以使用call子命令:

代码语言:javascript
复制
cast call 0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2 \
    "balanceOf(address)(uint256)" \
    0xf39Fd6e51aad88F6F4ce6aB8827279cffFb92266 \
    --rpc-url https://rpc.flashbots.net

这对0xC0...c2(WETH)地址执行balanceOf(address)查询,传递0xf3...66地址作为参数,并将返回数据解码为uint256类型的值。在这个和下面的cast子命令中,我们明确地使用了 Flashbots RPC,因为默认是http://localhost:8545

要查询一个地址的以太余额,我们可以使用balance子命令:

代码语言:javascript
复制
cast balance 0xf39Fd6e51aad88F6F4ce6aB8827279cffFb92266 \
    --rpc-url https://rpc.flashbots.net

我们也可以用 ENS 名称查询余额。

代码语言:javascript
复制
cast balance yourmom.eth --rpc-url https://rpc.flashbots.net

要提取合约上的合约状态槽内容,我们可以使用storage子命令。

代码语言:javascript
复制
cast storage 0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2 0 \
    --rpc-url https://rpc.flashbots.net

这将从0xC0...c2(WETH)地址中获得存储槽0内容。

Forge

Forge 是一个 CLI 工具,用于构建、测试、模糊测试、部署和验证 Solidity 合约。Forge 同样有很多的子命令,所以这里是参考文档[4]! 顺便说一下,如果你是来学习教程的,不需要运行这些命令,所有东西都包含在后面 创建 Foundry 仓库部分。

一个常用的子命令是 init,它可以初始化一个新的版本库:

代码语言:javascript
复制
forge init my_gigabrain_protocol

install子命令允许你安装指定版本的依赖项:

代码语言:javascript
复制
forge install Rari-Capital/solmate@v6

这将安装由Rari-Capital拥有的solmate软件库,特别是v6。注意,@v6是可选的。

为了运行测试,我们可以使用以下方法:

代码语言:javascript
复制
forge test

Anvil

Anvil 是一个 CLI 工具,用于运行本地 EVM 区块链。它可以与 ganache 和 hardhat 节点相媲美,但好像更快。

要启动 Anvil,只需使用 avil 命令:

代码语言:javascript
复制
anvil

你也可以指定一些参数, 用-v来显示详细日志,如果用-fork-url <FORK_URL>指定 URL 来分叉一个公共网络,等等。要查看 anvil选项的完整列表,可以使用以下命令:

代码语言:javascript
复制
anvil -h

创建 Foundry 仓库

初始化

为了开始工作,如上所述,我们将使用以下命令:

代码语言:javascript
复制
forge init my_token && cd my_token

这将创建一个my_token目录,初始化一个 git 仓库,添加一个 GitHub 工作流目录,安装forge-std包,生成一个foundry.toml文件,一个test目录,一个src目录,最后进入到my_token目录。

让我们继续,通过运行下面的程序删除现有的合约:

代码语言:javascript
复制
rm src/Contract.sol

现在,首先让我们看看foundry.toml文件,自动生成的文件应该是这样的:

代码语言:javascript
复制
[default]
src = 'src'
out = 'out'
libs = ['lib']

这将合约源代码目录设置为src,编译器输出目录设置为out,库的重新映射设置为lib

安装依赖

现在我们将安装一个依赖关系。我们可以使用<所有者>/<存储库>模式来安装Rari-Capitalsolmate

代码语言:javascript
复制
forge install Rari-Capital/solmate

这样就把solmate安装到了lib目录。现在让我们在src/MyToken.sol中创建一个 ERC20 合约。

我们可以导入并使用solmate的 ERC20 实现,如下:

代码语言:javascript
复制
// SPDX-License-Identifier: AGPLv3
pragma solidity ^0.8.13;

import {ERC20} from "solmate/tokens/ERC20.sol";

error NotMinter();

contract MyToken is ERC20 {
    address public immutable minter;

    // ERC20(name, symbol, decimals)
    contructor() ERC20("MyToken", "MyT", 18) {
        minter == msg.sender;
    }

    function mint(uint256 amount) external {
        if (msg.sender != minter) revert NotMinter();
        _mint(minter, amount);
    }
}

所以这是一个符合 ERC20 标准的代币,有一个简单的访问控制功能,用于铸币控制。

注意solmate/tokens/ERC20.sol导入是根据foundry.toml文件中指定的libs/目录重新映射的。

如果你使用 VSCode 并得到错误信息,可以尝试在项目根目录下创建一个remappings.txt文件并添加以下内容:

代码语言:javascript
复制
solmate/=lib/solmate/src/
forge-std/=lib/forge-std/src

编译

让我们继续编译合约:

代码语言:javascript
复制
foundry build

测试

现在我们需要写一些测试,因为一个掌管着不可忽视的价值的智能合约实际上是一个非自愿的 bug 赏金。不要让自己成为一个教训。:)

为了写测试,在test中创建一个文件。让我们创建一个名为test/MyToken.t.sol的文件。.t.sol表示这将是一个测试文件:

代码语言:javascript
复制
// SPDX-License-Identifier: AGPLv3
pragma solidity ^0.8.13;

import {Test} from "forge-std/Test.sol";
import {MyToken} from "../MyToken.sol";

contract MyTokenTest {
    MyToken internal myToken;
    address internal constant alice = address(1);
    address internal constant bob = address(2);

    function setUp() external {
        vm.prank(alice);
        myToken = new MyToken();
    }

    function testMint() external {
        vm.prank(alice);

        myToken.mint(1);

        assertEq(myToken.balanceOf(alice), 1);
    }

    function testFailMint() external {
        vm.prank(bob);

        myToken.mint(1);
    }
}

这里有一些代码需要解释:

forge-std导入的 Test默认是在 forge 创建 repo 时一起的生成的。它包括一个内部的vm变量,这是一个 cheat-code运行器。

vm包括一系列强大的“作弊代码”,例如:时间戳操纵 、将字节码刻在地址上、存储槽读写等。要查看所有这些代码,请看参考这里的介绍[5]。在这个例子中,我们使用vm.prank(address),其中的address参数将是下一个外部合约调用的msg.sender

要测试一个函数,在运行测试的函数的名称前加上test。在本例中,我们正在测试mint,所以我们可以叫它testMint。如果它不是以test开头,它将不会在forge test上运行。assertEq函数用来断言两个值是相等的。在Test合约中还声明了其他断言,可以在这里[6]找到参考。

要测试还原(revert),在函数名前加上testFail。在本例中,我们期望vm.prank(bob)失败,因为在setUp中,MyTokenmintervm.prank(alice)设置成了alice

现在我们来运行测试:

代码语言:javascript
复制
forge test

一切都应该通过。如果你需要调试函数调用,请在测试命令中加入 -vvvv (verbosity 4)。

代码语言:javascript
复制
forge test -vvvv

如果你需要从测试内部记录变量,你可以在Test中声明的事件。使用emit log_uint(uint)记录数字,你可以用emit log_named_uint(string,uint)来进行标记。要显示事件日志,在运行forge test时使用-vv(verbosity 2)。

本地部署

为了在本地部署合约,我们需要首先启动一个 anvil 实例。

代码语言:javascript
复制
anvil

当本地 devnet 开始运行时,这应该会打印出一些账户。让 anvil 运行实例单独使用一个终端窗口。

现在让我们从 anvil的输出中获取第一个账户的私钥,并将其设置为$PRIV_KEY环境变量。这不是必须的,它只是保持事情清晰。

代码语言:javascript
复制
export \
PRIV_KEY=0xac0974bec39a17e36ba4a6b4d238ff944bacb478cbed5efcae784d7bf4f2ff80

注意这些私钥是确定的,并且是公开的,所以在公共网络上投入资金之前要三思而后行。

现在验证私钥是否可以访问:

代码语言:javascript
复制
echo $PRIV_KEY

如果它打印出私钥,你就可以了。

现在把合约部署到本地 devnet 上:

代码语言:javascript
复制
forge create src/MyToken.sol:MyToken --private-key=$PRIV_KEY

这将加载到环境中的私钥,使用src/MyToken.sol文件中MyToken创建合约。请注意语法使用了明确指定的文件名称和合约名称:

代码语言:javascript
复制
forge create <filename>:<contractname> ...

在这种情况下,我们不需要构造器参数,但如果需要,则在最后传递--constructor-args标志,并写出构造器参数,用空格隔开:

代码语言:javascript
复制
forge create Filename.sol:Contractname \
    --private-key $PRIV \
    --constructor-args arg0 arg1 arg2

运行后,你应该在终端上打印出类似这样的东西。注意,你的合约地址和交易哈希值可能不同。

代码语言:javascript
复制
Deployer: 0xf39fd6e51aad88f6f4ce6ab8827279cfffb92266
Deployed to: 0x5fbdb2315678afecb367f032d93f642f64180aa3

Transaction hash: 0x3f849ddc766b4851fed8798a26aa6fe527c74cd9d6f2639ec289f5e11ceaa3b5

很好,现在我们可以使用 cast 来试用我们新创建的代币了。

同样,为了保持整洁,在终端环境中把你的合约地址导出为$CON_ADDRESS。如果你的地址不同,只需在下面的命令中替换它。

代码语言:javascript
复制
export CON_ADDRESS=0x5fbdb2315678afecb367f032d93f642f64180aa3

现在我们来查询 token 的.name()

代码语言:javascript
复制
cast call $CON_ADDRESS "name():(string)"

注意我们在函数签名中包括:(string)。这是为了帮助cast解码返回的数据,否则我们会得到一个巨大的十六进制字符串。

现在让我们使用部署该函数的同一私钥来调用 mint 函数。如果你使用任何其他的私钥则会失败,因为这是mint函数中的逻辑。

代码语言:javascript
复制
cast send --private-key $PRIV_KEY $CON_ADDRESS "mint(uint256)" 1

这会给我们的账户铸造 1 个代币,你也会注意到交易数据已经打印到屏幕上。真不错。

作为本地部署的最后验证,检查你账户的余额。如果你使用的私钥不是由 anvil 提供的,你可以随时使用以下方法:

代码语言:javascript
复制
cast wallet address --private-key $PRIV_KEY

再一次,为了方便,只需将钱包地址添加到环境中:

代码语言:javascript
复制
export WALLET=0xf39fd6e51aad88f6f4ce6ab8827279cfffb92266

现在进行余额查询。

代码语言:javascript
复制
cast call $CON_ADDRESS "balanceOf(address):uint256" $WALLET

这应该返回 1。

公共网络部署

部署在公共网络的工作原理与上述相同,当然是使用你自己的私钥、RPC 端点、链 ID。

合约代码验证

要用 Etherscan 验证你公开部署的合约,请使用以下命令:

代码语言:javascript
复制
forge verify-contract \
    --chain $CHAIN_ID \
    --compiler-version $COMPILER_VERSION \
    $CON_ADDRESS src/MyToken.sol:MyToken $ETHERSCAN_API_KEY

总结

Foundry 很强大,而且我们还只是从表面上看到了代工厂的兔子洞有多深。我希望这篇文章对你的编程和智能合约之旅有所帮助,并一如既往地做好黑客工作 🤘。


原文:https://medium.com/@jtriley15/the-foundry-evm-development-environment-f198f2e4c372

本翻译由 Duet Protocol[7] 赞助支持。

参考资料

[1]

Tiny熊: https://learnblockchain.cn/people/15

[2]

这里: https://book.getfoundry.sh/getting-started/installation.html

[3]

cast: https://book.getfoundry.sh/reference/cast/

[4]

参考文档: https://book.getfoundry.sh/reference/forge/forge.html

[5]

这里的介绍: https://book.getfoundry.sh/cheatcodes/

[6]

这里: https://book.getfoundry.sh/reference/ds-test.html#asserting

[7]

Duet Protocol: https://duet.finance/?utm_souce=learnblockchain

本文参与 腾讯云自媒体同步曝光计划,分享自微信公众号。
原始发表:2022-06-14,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 深入浅出区块链技术 微信公众号,前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 安装
  • Foundry 包含的组件
    • Cast
      • Forge
        • Anvil
        • 创建 Foundry 仓库
          • 初始化
            • 安装依赖
              • 编译
                • 测试
                  • 本地部署
                    • 公共网络部署
                      • 合约代码验证
                      • 总结
                        • 参考资料
                        相关产品与服务
                        区块链
                        云链聚未来,协同无边界。腾讯云区块链作为中国领先的区块链服务平台和技术提供商,致力于构建技术、数据、价值、产业互联互通的区块链基础设施,引领区块链底层技术及行业应用创新,助力传统产业转型升级,推动实体经济与数字经济深度融合。
                        领券
                        问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档