norah1499/solidity-flow-navigator
GitHub: norah1499/solidity-flow-navigator
SolFlow 是一款基于 Slither 的本地 Solidity 调用流可视化工具,为 Web3 安全审计人员将每个外部入口点的执行路径转化为带真实源码的交互式调用树图。
Stars: 0 | Forks: 0
# SolFlow
[](https://github.com/norah1499/solidity-flow-navigator/actions/workflows/ci.yml)
[](https://pypi.org/project/solflow/)
[](https://pypi.org/project/solflow/)
[](LICENSE)
**按照 Solidity 合约的执行路径来阅读,而不是按照其文件组织方式。**
SolFlow 会编译 Solidity 仓库,使用 [Slither](https://github.com/crytic/slither) 提取调用图事实,并为每个外部入口点提供一个交互式的调用流可视化(一个 **Flow**)。每个节点都会渲染目标函数的真实源码,并带有语法高亮和行号。分析完全在你的本地机器上运行。专为 Web3 安全审计而构建。

*SolFlow 在 [Morpho Blue](https://github.com/morpho-org/morpho-blue) 上的演示:从终端启动,浏览入口点索引,将 `liquidate` 流展开为其完整的调用树,然后切换到暗黑模式。可暂停的静态截图请见 [截图](#screenshots)。*
## 为什么需要
任何审计的首要任务都是重建当有人调用入口点时到底发生了什么。答案散落在十几个文件中的基础合约、库和修饰符里。SolFlow 将其以直观的图的形式展示出来。
## 功能
- **每个入口点一个 Flow。** 索引列出了每一个可被外部调用的函数,按合约分组,并区分为状态变更(mutating)或只读(read-only),每个入口都带有 modifier 徽章、调用树深度和未解析目标的统计:整个审计面一目了然。过滤框支持在输入时按签名或合约名称缩小列表范围,因此即使是拥有数百个入口点的协议也能轻松导航。
- **真实源码,而非简单的框图。** 每个节点都会渲染目标函数的实际代码,带有语法高亮和行号。点击调用处,被调用者会在其旁边展开,且边线会精确锚定在发起调用的那一行。
- **逐步展开或全局鸟瞰。** Flows 默认从根节点打开并按需展开,因此你只会展示当前正在追踪的路径。Flow 标题栏中的 **全部展开** 和 **全部折叠** 控件可以一次性切换整棵树,或者在启动时使用 `--expand-all` 以在页面加载时获取完整树视图。你展开的调用点会按 Flow 单独记忆,因此返回某个 Flow 时会完全恢复你之前打开的状态。
- **浅色或深色模式。** 标题栏的切换开关可以设置主题——自动(跟随你的操作系统)、浅色或深色——让漫长的审计过程更加护眼。该选择由服务器端渲染:加载时无闪烁,且你的偏好设置永远不会离开本地机器。
- **书签与最近查看。** 为你经常访问的入口点(和合约)添加书签——它们会汇集在索引顶部的 *已添加书签* 部分,可通过浮动快捷键从任何滚动位置直达。切换书签的操作是即时原位生效的,因此不会丢失你当前的浏览位置。你已经打开过的入口点在索引上会有高亮标记,方便你一眼看到进度。所有这些都通过本地 localhost cookie 实现——无需账号,数据不离开机器——并且即使禁用 JavaScript,这些切换功能依然有效。
- **绝不静默撒谎。** 当调用目标无法在静态分析下解析时(例如没有绑定实现的接口、`addr.call(...)` 或计算目标的 Yul),该节点会被明确标记为未解析,并附带具体原因。没有猜测,也没有静默的遗漏。审计员对 Flow 在其声明的范围内完整性的信任,是其最核心的价值所在。
- **可控的分析范围。** 通过 `solflow.toml` 或 CLI flags(详见 [配置](#configuration)),你可以内联某个依赖项、存根(stub)复杂的树内数学库,或者排除测试和模拟(mock)合约。
- **本地且私密。** 分析完全在你的机器上运行,且服务器仅绑定到 `127.0.0.1`。受 NDA 保护的审计代码绝不会被上传到任何地方。
## 前置条件
- **Python 3.11+**
- **与你目标项目匹配的 `solc`**,可通过 [solc-select](https://github.com/crytic/solc-select) 安装。Slither 需要它来编译项目。
## 安装说明
```
pipx install solflow
pipx install solc-select
solc-select install && solc-select use
```
如需获取最新的开发版本,请运行:`pipx install git+https://github.com/norah1499/solidity-flow-navigator`。
要卸载的话,`pipx uninstall solflow` 会删除该工具及其所有捆绑的依赖项;SolFlow 不会在其自身安装目录之外写入任何内容。`solc-select` 及其下载的编译器是独立的安装项,可通过 `pipx uninstall solc-select` 移除。
### 更新
使用 `solflow --version` 检查你安装的版本,并使用以下命令升级到最新版本:
```
pipx upgrade solflow
```
SolFlow 不会检查或通知你有关新版本的信息。它不进行任何形式的网络调用,这种纯粹的本地化和私密性机制确保了被审计的代码保留在你的机器上,因此没有用于检查更新的“回传(phone home)”操作。要获取新版本的发布信息,请关注 [GitHub releases](https://github.com/norah1499/solidity-flow-navigator/releases) 或 [PyPI 项目页面](https://pypi.org/project/solflow/),或者干脆时不时运行一次 `pipx upgrade solflow`。
## 运行说明
```
solflow path/to/your/solidity/project
```
将其指向 Slither 能够解析依赖项的仓库根目录。SolFlow 会编译项目,绑定到 `127.0.0.1:8080`(或下一个空闲端口),并打印出 URL。在浏览器中打开它即可导航各个 Flows。
编译过程依赖于 [crytic-compile](https://github.com/crytic/crytic-compile),因此它能检测到的任何构建系统都可以正常工作(Foundry、Hardhat、Truffle、Brownie、原生 solc)。SolFlow 目前主要针对 Foundry 项目进行测试。
## 配置
SolFlow 带有合理的默认配置。默认情况下,它会排除常见的测试和模拟目录(`**/*.t.sol`、`**/test/**`、`**/tests/**`、`**/mocks/**`)以及 `*Mock*` 合约。你可以通过配置文件、CLI flags 或两者结合来细化分析范围。CLI flags 会覆盖文件中的值;文件中的值会覆盖默认值。
### CLI flags
运行 `solflow --help` 获取完整的参考文档,这些选项被分为 **范围**、**解析**、**渲染** 和 **服务器** 四组。
| Flag | 作用 |
|------|--------------|
| `--exclude-path GLOB` | 丢弃文件路径与 glob 匹配的合约(可重复使用) |
| `--exclude-contract PATTERN` | 丢弃名称与模式匹配的合约(可重复使用) |
| `--inline-library NAME` | 递归进入 `lib//` 依赖项,而不是将其存根(可重复使用) |
| `--stub-path GLOB` | 为匹配的树内调用目标设置终端节点,例如复杂的数学库(可重复使用) |
| `--expand-all` | 打开每个 Flow 时全部展开,以便鸟瞰全局 |
| `--port N` | 绑定特定端口(默认从 8080 开始自动选择) |
| `--config PATH` | 使用工作目录中 `solflow.toml` 以外的配置文件 |
| `--version` | 打印已安装的 SolFlow 版本并退出 |
### 配置文件
SolFlow 会在你调用它的目录中寻找 `solflow.toml`。所有的键都是可选的;缺少的键将使用其默认值,将键设置为 `[]` 则会清除默认值。
```
[scope]
exclude_paths = ["**/*.t.sol", "**/test/**", "**/tests/**", "**/mocks/**"]
exclude_contracts = ["*Mock*"]
inline_libraries = []
stub_paths = []
```
## 工作原理
SolFlow 是一个基于 Slither 分析模型的轻量级流水线:
1. 通过 crytic-compile **编译** 仓库,然后从 Slither 提取原始事实:合约、函数、modifier、继承顺序、调用边和源码位置。
2. **为每个入口点构建一个 Flow**,并应用你的范围规则:modifier 被折叠到调用树中,virtual dispatch 通过 C3 链解析,跨合约调用根据绑定解析,且每个无法解析的分支都会被明确标记。
3. 通过本地的 Flask 服务器将 Flows 作为渐进式的 HTML+SVG 图形进行 **提供**,源码由服务器端的 [Pygments](https://pygments.org/) 进行高亮处理。
## 当首次运行失败时
SolFlow 构建于 Slither 之上且依赖于它:Slither 无法编译和分析的任何内容,SolFlow 也无法可视化。当这种情况发生时,SolFlow 会逐字打印底层的错误信息并退出,不会生成任何内容。
最常见的两种首次运行失败原因是环境问题,而不是工具本身的 bug:
1. **solc 版本不匹配。** 当前激活的 `solc` 与项目的 pragma 不匹配。解决方法:`solc-select install && solc-select use `。
2. **缺少依赖项。** 目标是全新克隆的,且其库从未被获取。解决方法:运行项目自身的设置(`forge install`、`npm install` 或等效命令),并确认其构建成功后再使用 SolFlow 进行分析。
如果项目可以干净地构建,但 Slither 本身仍然失败(这在某些大型协议中时有发生),这属于上游 Slither 的限制,而不是 SolFlow 的缺陷;当然,我们依然欢迎提交 [issue](https://github.com/norah1499/solidity-flow-navigator/issues),以便对其进行追踪。
## 截图
## 开发说明
欢迎提交 Issues 和 pull requests。在提交 PR 之前,请确保以下命令能够通过:
```
pytest
black --check .
ruff check
```
上述演示的静态截图 (Morpho Blue)
索引列出了被分析仓库的每一个外部入口点:  打开一个入口点会渲染其完整的调用流;每一个被调用者面板都显示了真实的源码:  标签:Slither, Solidity, Web3安全, 云安全监控, 代码可视化, 智能合约审计, 逆向工具, 静态分析