智能合约开发工具Remix

不久前,我在B站、视频号和 YouTube 都陆续发布了新的一套免费视频课程《智能合约开发工具Remix》,总共分为了 9 个小节的视频,以下分别是这 9 个小节在 B 站的视频链接,喜欢直接看视频的伙伴可以去 B 站观看:

  1. 概况

  2. 文件浏览器

  3. remixd

  4. Git插件

  5. 编辑器

  6. 编译器&AI工具

  7. 部署&发交易

  8. 调试器

  9. 单元测试

也可以在 B 站直接搜索「Keegan小钢」找到我,可以看到我目前发布的所有视频课程。截止到当前,我总共已经发布了 5 个视频合集:

而对于智能合约开发工具Remix这套课程,下面我再对每一节的视频,罗列出一些重点内容。

1. 概况

这一小节主要介绍了Remix的基本概况。

首先,记住 Remix 的正确域名是 https://remix.ethereum.org,避免被钓鱼。

其次,官方支持的浏览器只有 Firefox, Chrome, Brave 这三款而已,其他浏览器也许可以用,但不保证使用过程中会出现问题。

Remix 整个页面的布局主要分为了:

  • 图标面板:放置各种插件图标

  • 侧边面板:插件所显示的内容面板

  • 主面板:主页和编辑器面板

  • 终端:输出交易记录和日志等信息

默认插件有:文件浏览器、全文搜索、编译器、部署&发交易、Git。可以通过插件管理器添加和移除其他插件,常用的包括 Remixd、调试器、单元测试插件等。

切换不同插件时,侧边面板就会展示对应插件的内容页面。

2. 文件浏览器

文件浏览器插件,顾名思义,就是管理文件的。

第一个要熟悉的就是 Workspace,即工作空间,每一个工作空间就是一个项目。

有多种方式可以用来创建一个新的工作空间。可以创建一个空的工作空间,也可以基于模板创建,Remix 提供了很多模板。还可以通过克隆一个 Git 仓库的方式来创建。

可以创建多个不同的工作空间,也可以在不同的工作空间之间进行切换。

还可以对工作空间进行重命名、下载、删除、备份、恢复等操作。还可以通过 Remixd 插件连接到本地文件系统,关于 Remixd 部分则在第 3 小节中有详细介绍。

在工作空间下,也支持多种操作,除了直接创建文件和文件夹之外,还可以将本地文件系统的文件和文件夹加载上传到当前工作空间,也可以从 IPFS 或 https 方式导入文件。最后,还可以将当前工作空间初始化为一个 Git 项目。

3. remixd

默认情况下,Remix 里添加的文件是存储在浏览器自带的数据库 IndexedDB 里的,而浏览器数据库的存储并不是永久性的存储,所以建议增加其他文件备份和存储方案。使用 Remixd 把文件存储到本地的文件系统里就是其中一种推荐的方案。

要使用 remixd,需要在你的本地系统里先安装 remixd 命令行工具,可通过执行以下 npm 命令来安装:

npm install -g @remix-project/remixd

本地连接到 Remix 时,为了保证正常使用,要确保 remixd 已经更新到最新版本。可通过 remixd -vremixd --version 命令查看 remixd 的版本。如果版本还不是最新的,可直接通过以上安装命令升级更新到最新版本。

安装好 remixd 后,下一步可通过执行以下命令来启动 remixd:

remixd -s -u https://remix.ethereum.org

其中, 需要更换成你要连接的本地目录,比如,我要连接到 ./shared_project 目录,则实际执行的命令如下:

remixd -s ./shared_project -u https://remix.ethereum.org

启动成功后,在 Remix 里就可点击 “Connect to Local Filesystem” 打开确认连接到本地的弹出窗口,再点击 “Connect” 按钮就可建立连接了。

连接成功后,就会创建一个新的工作空间,与本地连接的目录相同。在 Remix 里对该工作空间的任何操作,都会同步到本地连接的目录中。同样的,对本地目录下的文件修改,也会同步到 Remix 里的工作空间里。

在本地执行 remixd 的终端窗口里,使用 ctrl-c 就可以关闭 remixd 了,也意味着断开了与 Remix 的连接。

4. Git插件

使用 Git 插件把 Remix 工作空间里的文件修改同步到 Git 远程仓库,也是推荐的另一种文件存储方案。

那要使用 Git,第一步需要先设置 Github 账号。进入 Git 插件面板,打开 GITHUB SETUP 选项卡,有两种设置方案:一是 Login with GitHub,会教你用三步骤来连接你的 Github 账号;二是手动输入你的 Git 用户名、邮箱和 Github token。

设置好 Github 账号之后,可以通过当前 Git 插件面板的 Initialize repository 按钮把当前工作空间初始化为 Git 项目。也可以创建一个新项目并勾选 ”Initialize workspace as a new git repository“。

当前工作空间变成一个 Git 项目之后,Git 插件面板所展示的选项卡也会多了很多。所有选项卡为:

  • SOURCE CONTROL:主要是做提交和同步操作

  • COMMANDS:可以执行 pull、push 和 fecth 操作

  • COMMITS:展示每一次提交

  • BRANCHES:用于创建分支、切换分支等

  • REMOTES:管理远程仓库地址

  • CLONE:克隆操作

  • GITHUB SETUP:设置Github

  • LOG:日志

完成了上一步的初始化之后,下一步需要设置远程仓库地址,在 Git 插件面板里的 REMOTES 选项卡里进行设置。

设置完之后,就可以对项目进行编码修改了,完成修改后。可通过 SOURCE CONTROL 添加 Commit 后执行 Sync Changes,就完成把代码推送到远程仓库了。

5. 编辑器

Remix 的编辑器,是和 VS Code 使用的同一款编辑器。其支持 Solidity、JS 和 TS 三种语言的代码高亮。

默认情况下,有三个特性很有用:

  • 代码自动补全

  • 展示 gas 预算

  • 展示错误提示

编码时,对于关键字和已声明的变量、函数名等都会有自动补全和提示功能。

对于每个函数,在函数右侧则会展示该函数的 gas 预算。

而对于代码中的 error 和 warning 则会用不同颜色的波浪线标记出来。

这几个特性都可在设置中进行开启或关闭,默认就是开启的。

另外,在编辑器中打开右键菜单,还可看到一个 ”Format Code“ 的选项,可以对当前代码进行代码风格格式化,使其符合代码规范,这一点也很方便。

6. 编译器&AI工具

编译器可以结合AI工具一起使用,比较方便。

编译器面板很简单,首先,可以选择编译器的版本,从 0.1.1 到最新版本全都有。其次,建议勾选上 "'Auto compile" 选项,则代码变更后会自动编译。然后,打开 ”Advanced Configuration“,建议把 ”Enable optimization“ 也给勾选上,值设为默认的 200 即可。

当代码里出现 errorwarning 时,在编译器面板里也会显示出这些错误提示信息,且在每个错误提示信息下面会有个 ”Ask RemixAI“ 的按钮,点击它,RemixAI 会针对该错误提示给出相应的回答,展示在终端面板里。

另外,在主面板左上角有个机器人的小图标,点击该小图标右边的切换按钮,还可启用 RemixAI Copilot。启用之后,能够增强代码自动补全的功能。比如,启用 RemixAI Copilot 后,进行 import 时,会自动显示出可导入的合约,包括第三方库如 @openzeppelin@uniswap,这一点非常方便。再比如,当你要定义一个函数时,输入完 function 后,也会给你提示可能想实现的函数声明,按 tab 键就可以自动补全整个函数声明,然后再根据自己实际要实现的代码进行调整即可。

编译器面板上有两个编译按钮,背景蓝色的按钮就只是编译合约文件,而灰色背景的 “Compile and Run script” 按钮则会在编译完成后自动执行指定的脚本文件。前提是在合约文件头部需要有声明 @custom:dev-run-script 的注解,并指定了要执行的脚本文件。比如,示例中的 Storage 合约的注解为@custom:dev-run-script ./scripts/deploy_with_ethers.ts,声明了 deploy_with_ethers.ts 脚本文件,该文件用 ethers 编写了部署 Storage 合约的脚本。那点击 “Compile and Run script” 按钮后,编译完 Storage 合约后,就会自动执行 deploy_with_ethers.ts 脚本,完成 Storage 合约的部署,部署成功的合约地址会在终端中打印出来。

在编译器面板最后有 ABIBytecode 两个选项,可以复制当前合约的 ABIBytecode,前端和后端需要和合约交互时就需要用到。

7. 部署&发交易

部署&发交易插件,先说部署。

第一步,选择部署的环境,即合约要部署的网络环境。默认下拉列表中有多个选项,点击列表中最后一项 “Customize this list..." 可以打开所有网络环境的列表。下面就只介绍最常用的几个。

  • Injected Provider - MetaMask:直接连接你浏览器中的 MetaMask 钱包,你的 MetaMask 钱包当前连接到哪个网络环境就使用哪个环境,钱包账户也是直接使用你的 MetaMask 账户。

  • Remix VM(Cancun):默认的内嵌浏览器的一个沙箱网络,并提供了 15 个默认账户,每个账户有 100 ether。

  • Remix VM - Mainnet fork:fork 自主网的浏览器沙箱网络,也提供了 15 个默认账户,每个账户有 100 ether。

  • WalletConnect:通过 WalletConnect 连接钱包

GAS LIMIT 部分一般直接选择默认的 Estimated Gas 即可,无需自定义数值。

VALUE 即需要转给合约的原生代币金额,即 msg.value 的值。

CONTRACT 里可选择要部署的合约,一般默认就是当前合约。

Deploy 就是部署按钮了,如果合约构造函数存在参数,则部署按钮旁边会显示出输入框,以输入参数。

部署成功后,在最下面的 Deployed Contracts 会展示出所部署合约的选项卡,打开它可以和合约进行交互。其中,蓝色背景的按钮是可读函数,橙色背景的按钮则是写函数。

还有个 At Address 按钮,也可用于加载合约到 Deployed Contracts 列表里进行合约交互。使用 At Address,有两种方式,一是CONTRACT 里选择要加载的合约代码,不一定需要完整合约代码,就算是只有 interface 也行;另一种方式,则是加载 abi 文件,视频里就使用了 IERC20.abi 作为示例演示。

8. 调试器

调试器插件,顾名思义,就是 Debug 用的。

有两种方式可以启动 Debug。第一种方式,直接在调试器面板中输入交易哈希,如果代码有 verify 的话,Remix 会尝试从 SourcifyEtherscan 获取源代码。第二种方式,也是更常用的方式,则是通过部署&发交易插件发起的交易,在终端里显示出每一笔交易时,右侧有个 Debug 按钮,点击该按钮就可启动 Debug 了。

Debug 时的基本操作有:

  • Step into:单步前进到下一个操作码,如果有子函数调用则会进入子函数

  • Step back:单步回退到上一个操作码

  • Step over forward:单步前进到下一个操作码,如果有子函数调用则不会进入子函数

  • Step over back:单步向后回退到上一个操作码,如果有子函数调用则不会进入子函数

  • Jump to next breakpoint:跳转到下一个断点

  • Jump to brev breakpoint:跳转到上一个断点

  • Jump out:跳出

  • Stop debuging:停止调试

面板中会展示出很多信息,最核心的就是操作码面板,会显示当前执行到第几步和对应的操作码。

另外,还有以下子面板:

  • Function Stack:函数栈

  • Solidity State:显示合约的状态变量

  • Solidity Locals:局部变量,包括函数参数

  • Step details:当前操作码的详细信息

  • Call Stack:调用栈

  • Full Storage Changes:显示函数末尾的持久化存储

  • Stack:EVM 栈

  • Call Data:包含了函数参数的 calldata

  • Memory:内存面板

  • Storage:持久存储面板

  • Return Value:返回值

  • Global Variables:全局变量

我在实际测试时,其实这些面板通常展示的信息并不全,比如,Solidity State 面板并没有显示出状态变量,Solidity State 也没有显示出全部局部变量,Return Value 也并没有显示出返回值。

9. 单元测试

最后一个插件,单元测试插件。

Remix 的单元测试插件支持的是 solidity 语言编写的单元测试用例代码。其用来声明断点的库文件是 remix_tests.sol,其中定义了 Asset 库,以及有多个 equalnotEqualgreaterThanlessThan 等函数。另外,还有一个 remix_accounts.sol 文件,其定义了 TestsAccounts 库,可通过其 getAccount 函数获取测试账户。

单元测试用例函数通常是以 checkXXX 命名的。另外,还有四个特殊函数:

  • beforeEach() - 会在每个单元测试用例之前执行

  • beforeAll() - 会在所有单元测试用例之前执行,只执行一次

  • afterEach() - 会在每个单元测试用例之后执行

  • afterAll() - 会在所有单元测试用例之后执行,只执行一次

编写单元测试时,还可以通过添加注解 #sender: account-{N}#value: {N} 来指定 msg.sendermsg.value,如下所示:

/// #sender: account-0
/// #value: 10
function checkSenderIs0AndValueis10 () public payable {
    Assert.equal(msg.sender, TestsAccounts.getAccount(0), "wrong sender in checkSenderIs0AndValueis10");
    Assert.equal(msg.value, 10, "wrong value in checkSenderIs0AndValueis10");
}

在单元测试插件面板中,还可以通过点击 Generate 按钮来自动生成测试文件。

点击 Run 按钮,则会开始执行单元测试了。如果存在多个文件的情况下,也可以勾选要执行哪些测试文件。

Subscribe to Keegan小钢
Receive the latest updates directly to your inbox.
Mint this entry as an NFT to add it to your collection.
Verification
This entry has been permanently stored onchain and signed by its creator.