<!-- BlazePhoenix — 技术白皮书，版本 2.3.0（机器可读，全文） -->
> 规范 PDF：https://blazephoenix.xyz/docs/BlazePhoenix_Whitepaper.pdf
> DOI：https://doi.org/10.5281/zenodo.23084091 （存档版本，v2.3）· 所有版本：https://doi.org/10.5281/zenodo.23084090 · 首个存档系列（v2.2）的概念 DOI：https://doi.org/10.5281/zenodo.22526574
> Litepaper（通俗语言配套文档）：https://blazephoenix.xyz/docs/BlazePhoenix_Litepaper.pdf
> 验证报告与兑换测试（2026 年九月），即本文引用的测量结果：
>   https://blazephoenix.xyz/verification-report-2026-09.md · https://blazephoenix.xyz/swap-tests-report-2026-09.md
> 本文件是白皮书的 markdown 完整文本，发布用于
> AI 收录与引用。内容许可：CC BY 4.0——引用时须注明
> BlazePhoenix 并附链接。本文所描述的 Solidity 源代码
> 在 2030 年之前采用 BUSL-1.1：请引用其架构，不得重新部署或
> 克隆。机器接口：/llms.txt · /facts.json · /knowledge-graph.jsonld
> 文内可引用的编号：创新 I-1–I-18、基本方程 E1–E42
> （附录 A）以及强制执行的不变量 INV-1–INV-31（附录 B）。

# BlazePhoenix-Dex

*英文原版 v2.3.0 的译文；以英文文本为准。*

**报价即成交。**

**可测量的交易所：报价与执行是同一次计算的链上流动性聚合器**

*技术白皮书——版本 2.3.0*

| | |
|---|---|
| 版本 | 2.3.0 — 2026-10-14 |
| 日期 | 2026-10-14 |
| 作者 | Mitra |
| DOI | [10.5281/zenodo.23084091](https://doi.org/10.5281/zenodo.23084091)（v2.3）· 所有版本 [10.5281/zenodo.23084090](https://doi.org/10.5281/zenodo.23084090) · 首个存档系列（v2.2）的概念 DOI [10.5281/zenodo.22526574](https://doi.org/10.5281/zenodo.22526574) |
| 所属机构 | BlazePhoenix — https://blazephoenix.xyz |
| 文本许可 | CC BY 4.0——引用时须注明出处并附链接 |
| 代码许可 | BUSL-1.1（Change Date 2030-06-01）——请引用其架构，不得重新部署 |
| 代码仓库 | `Blaze-Phoenix-Dex`，`main` 位于 `8916545`，2026-09-24 — https://github.com/blazephoenixxyz-crypto/Blaze-Phoenix-Dex |

> 你看到的价格，由执行你交易的公开代码、在执行它的那一帧中计算得出。任何人——包括作者——都无法更改费用或底线：它们是编译进去的。

## 十行。没有营销。

1. **没有服务器为你选择路由。** 执行它的交易从公开的池子状态中推导它。
2. **没有预言机为你的交易定价。** 池子来定价——在结算它的那一帧中读取。
3. **报价与底线是同一个求值器。** 价格没有可以漂移的缝隙。
4. **你的最低值是强制的。** Router 拒绝没有最低值的兑换。
5. **池子的声明可以免费伪造；它的实测输出不能。** 路由运行在后者之上。
6. **费用、分配与底线都已编译固化。** 不存在设置函数。任何人——包括作者——都无法改动它们。
7. **没有代理，没有升级路径，没有 `selfdestruct`，静止时没有余额。** 在两笔交易之间，Router 中没有任何可偷之物。
8. **恶意池子让你损失价格，然后回滚。** 它永远不会低于你的底线交付。
9. **这里的每个数字都与它的分母并列印出**——以及它可能被如何操纵。
10. **即使我们运行的所有服务器今晚消失，合约明天仍会报价、路由和结算。**

下文全部是证明：每项主张都附有强制执行它的代码行，以及约束它的界限。

## 摘要

BlazePhoenix-Dex 是一个建立在一个主张之上的链上流动性聚合器：报价与其执行是同一次计算。路由在执行它的交易内部、从公开的池子状态、由任何读者都能重新运行的无状态库推导出来；结算时具有约束力的数字由同一个调度器在执行帧内重新推导。没有路由服务，没有价格预言机，没有 keeper，也没有升级路径。本文规定五个合约——Core、Hub、Solver、Router、Quoter——以及元方程的各个算子：八重调度器 Ω、确定性推导 𝒟、Iron-Law 底线 Φ、活力场 Ψ 和反诈骗投影算子 Ξ。它们背后是同一条纪律——计量学设计：测量一切可以测量的坐标，并让其余部分保持单调，使虚假输入只伤害其提供者。每项保证都与其强制位置和界限一并陈述。验证体系连同其分母一起公布：236 个文件中声明的 1,609 项测试，268 个精选变异体中 268 个被杀死，针对 43 个有状态不变量的 15 个变异体中 14 个被察觉，强度 2（63 行，258 个对）与强度 3（168 行，1,636 个三元组）的覆盖数组，14 + 5 个蜕变关系，三个一致的优化器构建，以及一项关于报价如何老化的 240 样本研究。十八项有名字的创新支撑着整个设计，从元方程到穷尽免疫；在规范正文开始之前，每一项都连同其数学一并编目。在 Base、Ethereum、Optimism 和 Arbitrum 上线运行的一代是 V1；本文规定的是 V2，它已在其服务的每条链上、基于真实流动性的分叉进行了端到端演练。

## 如何阅读本文

每个机制先给出一句通俗的话，再给出一句精确的话，因此本文可以在两个深度上阅读：通俗的句子与图给出架构；精确的句子、表格与附录让你可以核验它。每项保证都是一句话——主张、强制它的位置、约束它的界限。六个算例用手算贯穿全部算术：一个恒定乘积报价（§4）、在两个池子之间的拆分（§10）、两跳路由上的 Iron-Law 底线（§11）、由其 key 推导出的 Uniswap V4 池标识符（§5）、同一路由上的两种费用制度（§13），以及对一次结算的解读（§11）。数字与其测量所依据的分母并列印出，复现它们的命令见附录 C。代码仓库是权威的：本文与源代码不一致时，以源代码为准。

## 创新

BlazePhoenix-Dex 不是一个拥有更好服务器的聚合器。它是一个**没有服务器**的聚合器——而要做到这一点，需要一组此前并不存在的机制。其中十八项支撑着整个设计。这里逐一列出每一项：它是什么、定义它的数学、它为什么对交易者重要，以及完整规定它的章节。

### I-1 · 报价 ≡ 执行

**是什么。** 给你的报价数字与约束你交易的数字来自同一个求值器——Core 的调度器 Ω——运行一次用于规划，并在执行帧内再次运行用于结算。整个系统中不存在第二个定价模型。

**数学。** 对每个分支 $\ell$，规划器与执行器在同一公开状态上求值同一个函数 $\Omega(p_{\ell}, x_{\ell})$；路由底线由该帧内的值重新推导（E15、E16），绝不从路由中读取。

**为什么重要。** 所有寄生于“服务器说了什么”与“链做了什么”之间缝隙的聚合器漏洞类别都无处容身。实测：无漂移报价按预测精确结算，**64 次中 64 次**，在 mock 上和在 Base 主网上皆然。（§3、§11、§12）

### I-2 · 链上求解器，免费调用

**是什么。** `Solver.findBestRoutePlan(tokenIn, tokenOut, amountIn)` 是一个 `view` 函数。任何人用免费的 `eth_call` 即可获得免信任的最佳路由——无需 API 密钥、无需中继、无需签名——而 `swapBestExactIn` 在一笔交易中原子地求解并结算。

**数学。** 整个 Solver 就是元方程（E1）在路由空间 $\mathcal{R}_{\mathcal{D}}$ 上的约束最大化，以确定性流水线执行：推导 → 排序 → 探测 → 过滤 → 分配 → 门控 → 底线。

**为什么重要。** 行业的路由智能运行在封闭服务器上，代码行数无从审计。我们的是 29,183 字节的公开字节码，任何人都能重新运行并得到相同答案。（§2、§10、§11.1）

### I-3 · 元方程

**是什么。** 整个聚合器，写成一个表达式。

**数学。**
$$R^{\star} = \arg\max_{R}\ \mathrm{net}(R)\cdot\prod_{\ell \in R}\hat{\Psi}(p_{\ell})\cdot\mathbf{1}[\mathrm{net}(R)\ge\Phi(R)]\cdot\Xi(R)$$

**为什么重要。** 乘积形式是一种安全属性：任何一个失败的因子——报价为零的分支、没有地位的池子、低于底线的路由、恶意钩子——都会让路由得分恰好为零。没有软惩罚，没有可调权重，没有差一点就合格的路由偷偷溜过。（§3）

### I-4 · 八重调度器 Ω

**是什么。** 六类交易场所——Uniswap V2、V3、V4、Algebra、Solidly stable 与 Solidly volatile——在一张属性表和一个调度器之后归结为四个数学族。

**数学。** 恒定乘积 $y = \lfloor x(\mathrm{BPS}-f)\,r_{\mathrm{out}} / (r_{\mathrm{in}}\mathrm{BPS} + x(\mathrm{BPS}-f)) \rfloor$（E2）；Q64.96 中的集中流动性，$\sqrt{P}' = L\sqrt{P}/(L + x_{f}\sqrt{P}/Q_{96})$，$y = L(\sqrt{P}-\sqrt{P}')/Q_{96}$（E3）；每个危险乘积都经 512 位 `mulDiv` 分解计算。

**为什么重要。** 碎片化原来是语言问题，而不是数学问题。每族一个经审计的公式为每条链上的每个交易场所定价；已知族的新分叉只是表中的一行，而不是新代码。（§4）

### I-5 · 确定性推导 𝒟

**是什么。** 池子是**计算**出来的，而不是询问得来的。Hub 由工厂、交易对和 init-code hash 推导每个候选地址，只接纳携带运行时字节码的地址。

**数学。** $\mathrm{pool} = \mathrm{addr}_{20}(\mathrm{keccak256}(\mathtt{0xff}\,\Vert\,\mathrm{origin}\,\Vert\,\mathrm{salt}\,\Vert\,\mathrm{initCodeHash}))$（E8）。

**为什么重要。** 工厂的回答可以被伪造；算术不能。发现过程对每个候选都无需外部调用，并在每条 EVM 链上以相同方式工作，池管理器与工厂作为运行时配置，绝不硬编码。（§7）

### I-6 · Uniswap V4，完全在帧内

**是什么。** V4 池子没有地址，也不响应调用。BlazePhoenix 推导它们的 id，对照 PoolManager 的存储**证明**每一个都真实存在，通过 `extsload` 读取价格与流动性，在最多十六段区间上遍历 tick 簿，通过单例合约（singleton）结算——包括原生 ETH——并仅凭算术筛查钩子。

**数学。** 存储基址 $\mathrm{slot} = \mathrm{keccak256}(\mathrm{abi.encode}(\mathrm{poolId}, 6))$，其中 $\sqrt{P}$ 位于位 [0,160)，LP 费用位于 [208,232)（E4）；钩子门控 $(\mathrm{uint160}(\mathrm{hook})\,\&\,\mathtt{0x3FFF})\,\&\,((1\ll3)\mid(1\ll2)) \ne 0 \Rightarrow$ 拒绝，无需调用（E18）；动态费用门控 E19。

**为什么重要。** 推导、证明、定价、筛查并结算 V4，而无需信任交易场所的任何一个回答——这是聚合器所能拥有的最深的 V4 集成，而且全部可在链上验证。（§5）

### I-7 · Solidly 稳定曲线求解器

**是什么。** 一个精确的、失败即关闭的求解器，用于 Aerodrome 和 Velodrome 类交易场所所使用的四次稳定曲线。

**数学。** 不变量 $k(x,y) = x^{3}y + xy^{3}$（E5），在小数归一化到 18 位（E7）之后，以有界牛顿迭代求解，附带对吃单方不利的一个单位增量，并以 64 步为上限（E6）。

**为什么重要。** 稳定币与流动性质押的流量集中在这些曲线上，在这里它们几乎把全部输入作为输出交付。求解器对它们精确报价——而在无法证明界限之处，它返回零而不是猜测。（§6）

### I-8 · 单槽（Monoslot）

**是什么。** 一个池子的全部路由状态——活跃度、深度等级、费用、类型、标志、新近度——打包进**一个 256 位字**。

**数学。** $s = a \,\vert\, f\!\ll\!8 \,\vert\, k\!\ll\!32 \,\vert\, r\!\ll\!40 \,\vert\, (c\wedge\mathtt{0xFFF})\!\ll\!48 \,\vert\, b\!\ll\!60 \,\vert\, \dots \,\vert\, B_{\mathrm{last}}\!\ll\!224$（E9）。

**为什么重要。** 一次 `SLOAD` 即可为池子排序；在一次 `SLOAD` 之上的一次 `SSTORE` 即可使其保持最新。而且这个字不包含价格，因此注册表的记忆在结构上就不可能给交易错误定价。（§8）

### I-9 · 自愈注册表与活力场 Ψ

**是什么。** 协议通过交易流动性来学习流动性。每个交易对十六个槽位，由真实兑换赢得的适应度分数，按算术衰减，以及一个**交易对证明**：池子在被存储之前，必须证明它交易的是哪些代币。

**数学。** $\Psi = V \cdot 2^{b} \cdot (1 + 0.25\,\mathbf{1}_{\mathrm{bridge}}) \cdot (1 + 0.05\,\mathbf{1}_{\mathrm{conc}})$（E10）；活跃度每沉寂 24,576 秒减半，$V = \mathrm{swapCount} \gg \lfloor (t - t_{\mathrm{last}})/24{,}576 \rfloor$（E11）；深度等级 $b = \min(15, \lfloor \log_{10}(d/10^{15}) \rfloor)$（E12）；新来者只有超过一个余量才能取代最弱者，$2^{b(d_{\mathrm{new}})} > \Psi_{\mathrm{worst}} + \lfloor \Psi_{\mathrm{worst}}/4 \rfloor$（E13）。

**为什么重要。** 没有 keeper，没有 cron，没有策展人决定哪些池子重要：注册表从用户本来就在发送的流量中自我修复。（§9）

### I-10 · 资本锚定的拆分

**是什么。** 价格质量与池子深度分开测量。一个微小的探测测量每个池子的边际汇率；一个以资本为锚的**可信带**剔除离群值；幸存者按实测深度比例分担订单。

**数学。** 中心 = 深度加权中位数——即满足 $\sum_{j \le i} d_{j} \ge \lceil \sum d / 2 \rceil$ 的第一个 $r_{i}$——可信带为 $[0.95, 1.05]\times$ 中心（E25）；只有当 $\mathrm{out}_{\mathrm{split}} \ge \mathrm{out}_{\mathrm{single}}\cdot(1 + 25/10^{6})$ 时拆分才保留（E14）。

**为什么重要。** 要移动锚点，攻击者必须存入超过该交易对一半真实流动性的资金——这是承担风险的资本，而不是免费的捐赠。长期有效的保证：**拆分的支付永远不少于最佳单一池子。** 在 Base 上对照穷举网格测量，Solver 的路由与最优解相差在 0.13 bps 以内。（§10）

### I-11 · Iron-Law 底线 Φ

**是什么。** 一个**在链上、在执行时**由实测价格冲击与路由集中度重新推导的最低输出——独立于调用者提供的任何内容。

**数学。** $\mathtt{floorBps} = \max(9{,}600 - \mathtt{legShv} - \min(\delta, 10^{4}) - \sigma_{\ln}/10^{14},\ 8{,}000)$（E15），其中集中度削减为 $\mathtt{legShv} = \sum_{\mathrm{hops}} \lfloor 200\,((\sum a)^{2} - \sum a^{2})/\sum a^{2} \rfloor$（E23）；交付必须达到 $\mathtt{effMin} = \max(\mathtt{userMinOut},\ \mathtt{route.singleOutFloor},\ \lceil \mathtt{finalHopQuote}\cdot\mathtt{floorBps}/10^{4}\rceil)$（E16）。

**为什么重要。** 调用者数据只能收紧保护，绝不能放松保护。在规模为深度 1 % 的交易上，底线把三明治攻击限制在交易额的约 2.7 %，超出即**拒绝**——越过边界后，攻击者的往返交易收益转为负值。（§11.5、§14.3）

### I-12 · 每道接缝都测量

**是什么。** Router 从不相信一笔转账已经发生；它去测量。每一次拉取、每一跳的到账和每一次交付都是真实的余额差值，从兑换的第一条指令一直到接收者的钱包。

**数学。** 每一跳都按其实测到账量重新缩放；恒定乘积分支上的转账收费（fee-on-transfer）代币按池子实际看到的差额定价，这正是池子自身不变量将要检查的那个量。

**为什么重要。** 会征税、会 rebase 或会误报的代币，无法迫使 Router 承诺它并不持有的东西——而 Router 在两笔交易之间**静止时不持有任何东西**（INV-1）。（§11.2、§11.4）

### I-13 · 单一回调原则

**是什么。** 一个 `fallback` 响应所有 V3 形态交易场所的闪电记账回调——Uniswap V3、Algebra、Pancake V3、Sushi V3、集中流动性的 Solidly 分叉——进行中的分支上下文保存在 EIP-1153 瞬态存储中。

**数学。** 应付代币由两个差值的符号读出；支付受三重约束——仅限已承诺的池子、仅在分支进行中、绝不超过该分支记录的预算（INV-10）。

**为什么重要。** 一个小巧的、三重防护的入口点取代了一大堆各分叉专用的回调——更少的字节码，更小的攻击面，只需验证一件事。（§11.4）

### I-14 · 盈余规则与穷尽免疫

**是什么。** 0.28 % 的费用，编译固化，在 Router 持有的第一个桥接币上收取一次——并且**没有任何随报价与交付之差增长的费用项。**

**数学。** $\mathrm{fee} = \lceil 28 \cdot \mathrm{base} / 10^{4} \rceil$，拆分为 $t_{1} = \lfloor 3{,}000\cdot\mathrm{fee}/10^{4} \rfloor$，$t_{2} = \mathrm{fee} - t_{1}$（E17）；制度谓词 $\mathrm{feeHop} = \min\{h : \mathrm{isBridge}(\mathrm{hops}[h].\mathrm{tokenIn})\}$（E26）。避开所有桥接币的路由在每一跳上都付费，因此任何粉尘前缀都无法把费用带走。

**为什么重要。** 池子交付的超出报价的一切都完整归你。费用不能针对某个交易者提高，也不能为受青睐的集成方降低——没有人持有那把钥匙。（§13）

### I-15 · 字节–gas 汇率 ρ*

**是什么。** Router 的四扇门是一个做成接口的仿射成本模型：在链上求解，或在 calldata 中携带预先求解的路由——哪个在该链上更便宜就用哪个。

**数学。** 当且仅当 $p_{\mathrm{byte}} < \rho^{*}$ 时在 calldata 中携带路由，按路由形态测得 $\rho^{*}$ 为每字节 66.9–105.5 gas（E22）。

**为什么重要。** 每条链对字节有一个价格，对计算也有一个价格。BlazePhoenix 测量两者之间的汇率，并把更便宜的那扇门交给交易者。（§17.6）

### I-16 · 反诈骗投影算子 Ξ

**是什么。** 任何其 V4 钩子声明了改变差值权限的池子，都会在**排序之前**从候选集合中移除，而钩子根本不会被调用。

**数学。** 元方程中的 $\Xi(R) \in \{0,1\}$，通过对钩子地址的 E18 位测试求值。

**为什么重要。** 恶意钩子永远没有机会撒谎：它从未被询问。三个独立的防护层——地址位、按 codehash 锁定的允许列表，以及 Ξ——挡在交易者与恶意交易场所之间。（§5.5、§14.2）

### I-17 · 单向门

**是什么。** 管理权限在字节码中不可逆地终止。`renounceControl` 写入一个任何代码路径都无法撤销的标志；此后只剩下一个只增不减的策展人层级。

**为什么重要。** “我们不会动它”变成“我们无法动它”。费用、分配与底线从一开始就不可设置（INV-4）；门关上之后，其他一切也不可设置。（§14.7）

### I-18 · 计量学设计与公开的分母

**是什么。** 上述一切背后的纪律——测量一切可以测量的坐标，让其余部分保持单调，使虚假输入只伤害其提供者——以及一个**把每个数字与其分母并列报告**的验证体系。

**数学。** 236 个文件中声明的 1,609 项测试；268 个精选变异体中 268 个被杀死，每个都与一项必须失败的测试配对；在制度因子上强度 2（258 对中的 258 对）与强度 3（1,636 个三元组中的 1,636 个）的覆盖数组；14 + 5 个蜕变关系；三个逐位一致的优化器构建；Halmos 与 Certora Prover 中的符号证明。

**为什么重要。** 大多数项目公布测试数量。BlazePhoenix 公布其证据可能如何被操纵、以及它依据什么来测量——并在每次提交时重新计算。（§2.3、§15）

### 记分板

| 实测属性 | 结果 |
|---|---|
| 按预测精确结算的无漂移报价（240 样本研究） | **64 / 64** |
| 交易场所异常 × 门，以我们自己的选择器结算或拒绝——绝无第三种结果 | **20 / 20** |
| 被杀死的精选变异体 | **268 / 268** |
| 其拒绝由精确代码演练的控制操作 | **31 / 31** |
| 在两处计算、由一项具名测试绑定一致的量 | **7 / 7** |
| 按构造演练的制度因子取值对 | **258 / 258** |
| 按构造演练的制度因子取值三元组 | **1,636 / 1,636** |
| 报价数学的优化器构建结果一致（runs 1 / 300 / 20,000） | **3 / 3** |
| 四条链上的预览 → 交付 | **0–1 bps** |
| Solver 路由 vs. Base 上的穷举网格 | **相差在 0.13 bps 以内** |
| 在规模为深度 1 % 的交易上，底线允许的最大三明治攻击，超出即拒绝 | **≈ 2.7 %** |
| 致谢的外部安全研究人员 · Critical 级发现 | **25 · 0** |


## 目录

- 创新（I-1–I-18）与记分板
- §1 问题：报价是别人计算出来的承诺
- §2 答案与纪律：不变量驱动的设计与计量学设计
- §3 元方程与依赖预算
- §4 八重调度器 Ω——类型、族、闭式解
- §5 Uniswap V4 端到端——单例合约、存在性证明、费用门控、钩子
- §6 Solidly 求解器
- §7 确定性推导 𝒟
- §8 单槽（Monoslot）
- §9 自愈注册表与活力场 Ψ
- §10 路由与拆分分配器
- §11 执行层与 Iron-Law 底线 Φ
- §12 报价接口，以及报价如何老化
- §13 费用政策：两种制度与盈余规则
- §14 安全模型
- §15 验证体系，实测
- §16 架构与规模
- §17 实测性能
- §18 剥到只剩骨架的 DEX
- §19 部署状态
- §20 代币——BZPX
- §21 研究计划与安全记录
- §22 你必须信任什么，以及无须信任什么
- §23 相关工作
- §24 结论
- §25 Staking V4：设计
- 附录 A · 基本方程（E1–E42）
- 附录 B · 不变量（INV-1–INV-31）
- 附录 C · 复现命令
- 术语表
- 参考文献

---

## §1 问题：报价是别人计算出来的承诺

想象在一座有二十家经销商的城市里卖一辆车。一个好的经纪人会拜访全部二十家，找到最好的价格，或许还会把这笔交易拆分给其中两家。大多数链上“经纪人”在自己的数据库上查价——数据可能已经过时——然后把结果展示给你。你无法验证他们是否查看了全部二十家，也无法验证他们给你看的是否是最好的那一家。你只能验证，到目前为止，他们一直是诚实的。

我们读过其文档的每一个聚合器——1inch、CoW Swap、Velora（ParaSwap）、KyberSwap、OpenOcean、Jupiter 和 UniswapX，以 2026-09-07 的文档为准——都是这样工作的：一个服务在链下计算路由，合约执行交给它的路由。合约不做选择；它只做检查。这是稳健的工程——正因如此，这些系统才又快又便宜——但它有一个很少被直白说出的后果：**这样的系统所能做出的最强主张，就是其运营者是诚实的。**

这道缺口通常不是欺诈，而是漂移，来自三个寻常的来源。报价所依据的储备在交易上链之前已经变动。搜索的穷尽程度只取决于运营者的预算。而报价与成交之间的每一次修正——滑点缓冲、途中的一笔费用——都由用户没有读过的代码施加在一个用户无法复现的数字上。这些都不需要恶意。但这一切都是不可见的。

### §1.1 碎片化是真实的，但比看上去更浅

想要最佳价格的交易者面临一个悖论。流动性是存在的，分散在几十个去中心化交易所中，每个都有自己的池子合约、自己的定价曲线、自己的地址方案——但没有哪一个交易场所持有全部流动性。最佳执行的代价，是同时讲每个交易所的语言的成本，以及信任从展示的价格到落地的交易之间每一位翻译者的成本。

现有的答案是一次集成一个交易场所：为 Uniswap 写一个连接器，为 Solidly 分叉再写一个，为每种集中流动性变体各写一个，每个都有定制的报价、定制的地址查找、定制的执行。集成面随交易场所数量线性增长，而每个连接器都是定价缺陷、或报价数字与执行数字之间无声错配的又一个新出处。

碎片化比看上去更浅。在表面的多样性之下，持有大部分链上流动性的自动做市商受一小组不变量支配。恒定乘积池服从 $x \cdot y = k$。集中流动性池在分段恒定的活跃流动性之上，以定点数追踪平方根价格。Solidly 族在其稳定交易对上服从四次方程 $x^{3}y + xy^{3} = k$，在其波动交易对上服从恒定乘积。形状只有寥寥几种，而不是六十种。

如果形状很少，聚合的成本就不必随交易场所数量增长；它只需随形状数量增长。一个把每种形状正确实现一次、并把每个交易场所调度到正确形状的协议，会把集成面从线性压缩为常数。新增一个交易场所不再是工程，而变成配置：分配一个类型和一种地址推导模式，现有的数学就为它定价，现有的路由器就为它结算，现有的注册表就学习它。

**设计的核心主张：** BlazePhoenix 路由经过的每个交易场所，都是一小族输出函数之一的参数化——在六类分类法之上的四个工作族（§4）——它们只保存一次，位于单一的无状态库中，并且从不重新定义。新增一个交易场所意味着分配一个类型和一种推导模式，而不是编写新的定价代码。

### §1.2 链下逃生舱

主流的聚合器架构在一组服务器上为路由报价，在链下求解器之间进行拍卖，用 keeper 机器人为池子流动性建立索引，再把结果交给一个轻薄的链上结算合约——这个合约常常位于一个可升级代理之后，其管理员密钥可以直接替换逻辑。一个 Web 服务产生价格，一个数据库保存流动性图，一个特权运营者可以改变规则，而链沦为在别处做出的决策的结算场所，这些决策由用户看不到、也无法验证的软件做出。

这种安排恰恰重新引入了这项技术本应消除的信任。链下报价可能与链上成交不同，而用户无法证明它本不该如此。keeper 可能掉线，路由器随之失明。代理管理员可以在一笔交易中把一个诚实的合约变成一个恶意的合约。

| 关注点 | 链下求解的聚合器 | BlazePhoenix-Dex |
|---|---|---|
| 报价 | 链下服务器或求解器拍卖 | 一个链上调度器，由预览与帧内执行共享 |
| 流动性发现 | keeper 机器人建立索引并推送列表 | 自愈注册表——通过交易流动性来学习流动性——外加确定性发现 |
| 路由选择 | 专有的链下优化器 | 链上 Solver，任何人都能从公开状态复现 |
| 升级面 | 由管理员控制的代理 | 无状态 Core；没有代理，没有升级路径，没有 `selfdestruct` |
| 对资金的特权 | 常常存在 | Router 静止时不持有任何东西；没有函数能转移用户本金 |
| 跨链一致性 | 每条链各自的后端逻辑 | 每条链一份字节码 |
| 信任假设 | 运营者的诚实 | 用户自己的最低值，合约拒绝接受其为零 |

BlazePhoenix 拒绝这笔交易的两半。它通过证明集成面并非线性来拒绝线性集成面，并通过把整个决策——发现、报价、评分、路由与结算——保留在任何人都能阅读、在每条链上都给出相同答案的合约之内来拒绝链下逃生舱。代价是真实的：在链上为集中流动性池报价比从数据库读取更昂贵。这份代价买到的是消除一类故障——服务器承诺的与链交付的之间那种无声的、无法证明的背离。之后的每一个设计决策都是这一取舍的实例。

## §2 答案与纪律

**做选择的，就是执行交易的。**

BlazePhoenix-Dex 有一个入口，接受六个值——两种代币、数量、你的最低值、接收方、截止时间——并在执行它的交易内部，根据作为公开状态的池子储备算出路由：用哪些交易场所、各分配多少、按什么顺序。由于路由是由公开代码从公开状态推导出来的，任何人都能重新推导它。由于结算时具有约束力的数字由同一个调度器、在同一帧中、从同一份实时状态重新推导，报价与执行不是两个需要对账的产物；它们是同一次计算，区分预览与成交的是时间，而不是第二个模型。

另外三个入口从 calldata 接受预先计算好的路由，供那些想走更便宜的路径、并愿意自己提供答案的调用者使用；同一套测量、底线与结算机制适用于全部四个入口（§11）。我们不主张链下方案是错的，也不主张自己更便宜。我们主张的是另一类保证——可审计的，而非承诺的——提供给想要它并愿意为它支付 gas 的用户。

据我们所能确认，这一设计中有四项决策在业内并不常见，每一项都附带让它保持诚实的边界。

- **地址是推导出来的，而不是获取来的。** 凡是交易场所族的部署可复现之处，池子地址都由 CREATE2 算术计算——一个任何人都能从三个公开输入重新验证的定理——而不是从工厂的存储中读取；在算术不可靠之处，协议会去询问，而被询问的池子在被列入之前必须证明自己的交易对（§7）。
- **池子的路由状态是一个字。** 单槽（Monoslot）把为交易场所排序所需的一切打包进一个 256 位槽，并刻意不包含任何价格，因此注册表的记忆可以影响去询问哪些池子，但在结构上无法为交易定价（§8–§9）。
- **底线根据实际发生的交易重新推导。** Router 在执行帧内测量每条分支的实际冲击和每一跳的实际集中度，并据此重新计算底线，因此调用者提供的字段只能收紧保护，永远不能放松它（§11）。
- **在交易场所没有地址之处，发现过程不依赖部署者。** 对于 Uniswap V4 单例合约（singleton），池 ID 由公开参数推导，再对照管理器自身的存储证明其存活——这是别人无法伪造的证明（§5）。

这些都无法消除每个聚合器都背负的残余风险——状态可能在签名与上链之间变化——这正是为什么你自己设定的最低值是强制的，并且是最终的：每个入口都会在任何代币移动之前以 `RouterE(10)` 拒绝零最低值。

### §2.1 不变量驱动的设计

答案背后是一种方法。我们称之为不变量驱动的设计：协议不是被规定为一串操作，而是被规定为一组在每个可达状态下都必须成立的性质，代码的组织方式使这些性质成为结构性的——由代码的形状强制，而不是靠程序员的警觉。

大多数软件以命令式编写，正确性只是一种自然涌现的希望。对普通软件而言这可以接受，因为故障可以恢复。在公链上，这些都不成立：代码一经部署便不可更改；它直接托管价值；它在对抗性环境中执行，每一个边界都有人在搜寻；一次算术失误就是不可逆的损失，而不是一次崩溃。

不变量是一种无论系统如何到达当前状态都为真的性质。*Router 在交易之间不持有资金。* *一个注册表交易对最多容纳十六个池子，驱逐保留最适应的十六个。* *不存在未支付协议费用的结算。* 三条原则把这类陈述置于中心：

| 原则 | 陈述 | 体现之处 |
|---|---|---|
| 计算，而不是信任 | 凡能推导或证明的值，绝不获取或假设。 | 𝒟 计算池子地址；Router 在帧内根据实测余额重新推导费用基数与底线。 |
| 唯一真相来源 | 每个数学原语只定义一次并被导入；绝不重述。 | Core 持有全部定价、推导、底线与评分数学；Hub、Solver、Router 和 Quoter 导入它，没有一个重新定义原语。共享量登记表（§15）为每个有两个生产者的量评级。 |
| 失败即关闭 | 当某个性质无法保证时，停止，而不是凭猜测继续。 | Solver 宁可不返回路由，也不返回伪造的路由（`SolverE(5)`）；稳定求解器返回零，而不是饱和的报价（§6）；注册表的一致性守卫在写入任何状态之前回滚结构上不可能的交易场所（§9）。 |

第四条原则约束托管：**没有通往资金的特权路径。** Solver 和 Quoter 是只读路径合约；Router 是唯一移动资金的合约，它在用户自己设定的界限下原子地移动资金，而每一项可能改变资金去向的管理权限都可以通过单向门（§14）永久交出。

### §2.2 为什么这种纪律适合这种媒介

环境中让命令式代码变得危险的每一个性质，都被不变量驱动的代码转化为优势。不可变性奖励可证明性：已部署的代码无法打补丁，因此事先证明的价值相应地高。可组合性奖励唯一真相来源：一个定价函数可能在其作者从未预料到的金库中被调用，而只有一个 Core 时，每个调用者都得到同一个答案。对抗性奖励失败即关闭：攻击者只需要一条作者没有考虑到的路径，而一个在假设被打破时就停止的系统让他们无从即兴发挥。利害攸关的价值奖励可读性：一个表达为作用于同一数学核心的五个具名算子的协议，可以由并非其作者的人逐行检查。

这种纪律并非免费，而这种取舍是刻意的：证明溢出界限比假设它不存在更费时间；让每个乘积都经过全精度乘除，比朴素乘法多花 gas；推导地址需要的工程投入，正是直接获取地址所省掉的。这意味着在部署前付出更多成本，以换取消除部署后无法恢复的故障。

### §2.3 计量学设计：一个态射、实测坐标、单调输入

不变量驱动的设计说明什么必须始终成立。另外三条规则说明维护它的代码是如何*成形*的，它们共同构成一种我们在业内其他地方未见命名的方法，因此本文为它命名：**计量学设计**——把合约构建成一台*仪器*。它的论点一句话：*相信的代码是攻击面；测量的代码是防线。*

**一个态射，在某一点求值。** 聚合器并不为每个交易场所包含一套集成；它是在空间（交易场所形状、链、费用模型）中的某一点对一个参数化定价态射的求值。若表达为代码分支，六种左右各有自己费用约定的活跃交易场所类型，会成倍增长为数百种两两组合——字节码成倍增长、审计面成倍增长、漂移成倍增长。若表达为态射，同样的覆盖只是少数几种*状态形状*、一个无状态的 Core、以原生单位携带的费用约定，以及注册表——字节码以*加法*方式增长：新的交易场所是一行，而不是一个代码分支。守护这种坍缩的规则是 `KIND → SHAPE`：交易场所族是*数据*——分配给现有形状的一种类型加一种推导模式——绝不是一条可由对抗性输入选择的新代码路径。Core 以位表（`THETA_ATTR`，§4）陈述这些形状，因此“这种类型读取储备吗？”只是一次移位和一次 AND，也不存在任何人可能遗忘的默认代码分支。这种坍缩有一道刹车：不存在单一的通用公式。两种闭式被精确求值——恒定乘积与集中流动性——而对于每一种复制会成为负担的曲线，则去询问交易场所自身的字节码（§6）。态射坍缩的是*成员归属*，绝不是*验证*。

**坐标是测量出来的，绝不是相信来的。** 凡存在链上测量之处，合约绝不依据建模的、名义的或调用者提供的值行事——也没有任何无需许可的数据能选择运行哪段代码。由不受信任方提供的数据——路由、声明的费用、声称的深度、池 ID——都是*坐标*：仪器所指向的位置，合约随后自行读取，失败即关闭。本文中每一项承重的防御都是它的实例：测量拉取后的余额，而不是名义数量（§11）；费用基数取自实测余额差，而不是 calldata（§13）；可信带锚定在实测深度的深度加权中位数上，而不是可被捐赠抬高的原始余额上（§10）；容量钳制以实测持有量为准进行截断（§10）；V4 费用闸门读取实时状态，而不是信任哨兵值（§5）；存在性证明式的发现读取单例合约自身的存储（§5）；以及被询问的池子在被发现过程列入之前证明自己的 `token0`/`token1`（§7）。代码仓库按这条规则公开了每个调用者可写字段的分类：23 个字段，14 个已对照观测确认，5 个起引导作用，4 个已声明并附理由（§15）。

**测量止步之处，单调性登场。** 有些数字既不能测量，也不能重新推导——调用者的底线、调用者声明的缩放、调用者自己的最低值。对于这些，设计接受该数字，并把函数塑造成撒谎只会伤害撒谎者：路由所证明的底线只能*抬高*强制执行的底线（§11）；当某条分支证明的报价不足以覆盖实测报价时，它会被提升到实测报价（§11）；声明的缩放以实测到达量为上限，因此夸大无法路由从未存在的资金；而协议无法替你选择的那个数字——你的最低值——是强制的。单调输入不需要信任，因此它可以在链下由任何人免费计算，并放在 calldata 中携带——这就是本协议如何把工作移到链下*而不把信任移到链下*，也是 Router 能够以相同保证同时提供一个求解入口和三个 calldata 入口的原因。

计量学设计同样约束围绕这件产物的工程，因为仪器的好坏取决于它的校准。安全裕度根据实测风险定价：拆分闸门设在 25 ppm，因为分支的盈亏平衡点实测为 3 ppm（§10）；一项比其实测风险高出 27× 的规划折扣已被撤除（§10）。外部比较要么附带其方法的误差棒，要么不予刊出（§17）。而测量装置本身也被测量：每一种保证工具在其数字刊出之前，都已对照一个通过其他途径已知的缺陷完成校准（§15）。这就是全部理论；本文其余部分是它的实践。

## §3 元方程与依赖预算

整个聚合器可以被理解为对一个表达式的最大化。给定输入代币 $t_{\mathrm{in}}$、输出代币 $t_{\mathrm{out}}$ 和数量 $x$，Solver 在可接纳路由中搜索使净收到价值最大的那一条，并受可行性底线与反诈骗闸门约束：

$$
R^{\star} \;=\; \mathrm{arg\,max}_{\;R \,\in\, \mathcal{R}_{\mathcal{D}}(t_{\mathrm{in}},\, t_{\mathrm{out}},\, x)} \;\; \mathrm{net}(R)\cdot\prod_{\ell\in R}\hat{\Psi}(p_{\ell})\cdot \mathbf{1}[\,\mathrm{net}(R) \ge \Phi(R)\,]\cdot \Xi(R)
$$
^e1

$$
\mathrm{net}(R) \;=\; \sum_{\ell\in R}\Omega(p_{\ell},\, x_{\ell})\;-\;f_{\mathrm{proto}}
$$

其中 $\mathcal{R}_{\mathcal{D}}$ 是由确定性推导 𝒟 和注册表所定位的池子构成的路由空间；$\Omega(p_{\ell}, x_{\ell})$ 是调度器对分支 $\ell$ 把 $x_{\ell}$ 推过池子 $p_{\ell}$ 时给出的输出；$f_{\mathrm{proto}}$ 是协议费用；$\hat{\Psi}(p_{\ell})$ 是该分支的归一化活力；$\Phi(R)$ 是针对路由实测冲击与集中度的 Iron-Law 底线；$\Xi(R) \in \{0, 1\}$ 是反诈骗投影算子。

| 算子 | 名称 | 在方程中的作用 | 章节 |
|---|---|---|---|
| Ω | 八重调度器 | 为每条分支定价——每种池子类型一个代码分支——并为拆分分配器报告以代币计价的深度 | §4 |
| 𝒟 | 确定性推导 | 定位路由所用的池子：在族允许时通过计算地址，对 V4 单例合约则通过经证明的池 ID | §5, §7 |
| Φ | Iron-Law 底线 | 把路由投影到可行集上：净输出之下的底线，在执行帧内重新推导 | §11 |
| Ψ | 活力场 | 按挣得的质量为每个池子加权，从其打包的链上状态读取 | §9 |
| Ξ | 反诈骗投影算子 | 把任何不宜展示的路由的价值恰好定为零 | §5, §14 |

这种因子分解是刻意的。Ω 回答*池子返回多少*；Ψ 回答*该信任它多少*；Φ 回答*路由是否可接纳*；𝒟 回答*池子在哪里*；Ξ 回答*路由是否可以安全展示*。乘积形式意味着单个失败的分支就会让路由得分坍缩——报价为零的分支，或没有资历的池子，会把乘积清零，而不是打折——而指示函数会把任何净输出低于底线的路由硬性清零。没有软惩罚，没有可调权重，没有险些达标的路由蒙混过关。

![FIG-1 — 元方程作为 Solver 的流水线：候选来自 𝒟 和注册表，由 Ψ 排序并截断，由 Ω 报价，在各分支间分配，对照 Φ 与 Ξ 检查；Router 在执行帧内重新求值 Ω 与 Φ。](https://blazephoenix.xyz/whitepaper/figs/zh/fig-1.png)

在链上，Solver 将该方程实现为一条流水线（`findBestRoutePlan`）：每个交易对的候选由注册表收集，并在注册表不新鲜时由 𝒟 收集；由 Ψ 排序并截断到 `MAX_CANDIDATES = 8`；由 Ω 探测并报价；经可信带过滤；在各分支间分配；组装好的路由携带 Φ 所证明的底线。随后 Router 根据实际到达的数量重新求值 Ω 与 Φ。方程所作的主张——审计者可以据此检验代码的主张——是该流水线的任何一步都不参考五个算子之外的任何东西。如果一个量不是五个算子之一的参数，它就无法影响路由：任何交易场所的营销、任何链下声誉、任何运营者偏好都不能。

### §3.1 依赖预算

与其使用形容词——*去中心化*、*无服务器*、*免信任*已经不再承载信息——不如给出可检查的清单：一笔交易要完成结算，必须存在并持续工作的一切。

| 依赖 | 典型的链下求解聚合器 | BlazePhoenix-Dex |
|---|---|---|
| 计算路由的服务 | 必需 | 不使用——Solver 是任何节点都能提供的 `view` 函数 |
| 价格预言机（oracle）或喂价 | 视情况而定 | 无——五个合约中不存在任何喂价调用 |
| 求解器网络或拍卖 | 常见 | 无 |
| keeper、定时任务或中继 | 视情况而定 | 无——活力在下次被读取时按算术衰减；注册表从普通交易中学习 |
| 可升级代理 | 常见 | 无——没有代理，没有 `selfdestruct`，没有初始化函数；唯一的 `delegatecall` 是编译器自身对公开 Core 库的调用，在链接时固定 |
| 托管的界面 | 实际上需要 | 仅为便利 |

最后一行正是大多数预算悄然失守之处。托管界面是一种便利，而不是依赖：`swapBestExactIn` 接受六个人工即可拼出的值，集成方、脚本或竞争对手的前端都可以调用它，而无需与我们有任何关系。即使本项目运营的所有服务器今晚消失，合约明天仍会像今天一样报价、路由和结算。这一性质的代价是调用者以 gas 为搜索买单；上面的预算，就是 gas 所赎买的那些东西的清单。

不可变性也有另一面。缺陷无法打补丁——这是只需审计一次的合约所付出的代价——因此缺陷改为公开披露并设立赏金（§21）。

### §3.2 三条边界

预算有三条边界，与它们所限定的主张并列陈述。界面是托管的，和所有人一样，而被攻破的前端是威胁模型中最大的单一暴露面：合约会遵从交给它的任何非零最低值，因此你设定的最低值是任何界面都无法从你手中夺走的那道界限。交易场所发现读取的是更早的交易写入的状态——公开且无需许可，但不是在交易时凭空变出来的。管理权限在通过单向门放弃之前一直存在；放弃之后，控制层——暂停、角色、金库、连线、移除——永远消失，只剩下只增不减的策展层（§14）。无状态核心、无服务器运行、只增不减的治理：表格就是主张；文字只是它的影子。


## §4 八重调度器 Ω

*通俗地说：*一个知道如何为每种池子定价的函数。*精确地说：*Core 中的 `universalQuote(QuoteCtx, amountIn)` 是 Solver 和 Quoter 预览所用的报价调度器；它返回预期输出和供拆分分配器使用的以代币计价的深度，无法定价的池子返回零，并在任何资金发出之前被剔除。Router 在自己的帧内对每条分支求值同样的 Core 原语（`_hopScaleImpactAndQuote`），这是一个为了 gas 和栈深度而保留的姊妹实现；Quoter 的 Exact Pass 问的又是另一个问题（§12）；三者一同记录在代码仓库的共享量登记表中，它们的一致性由具名测试锁定，而不是假设（§15）。这个内部名称沿用自调度器发布时的八类枚举；此后该枚举增加了第九个成员，并刻意切除了三个。编号保留其空缺：昨天记录的 Monoslot 必须永远以相同方式解码。

### §4.1 六种类型、四个族、一张属性表

| 类型 | 常量 | 族 | 定价方式 | Θ 属性 | Gas 阶梯（Solver） |
|---|---|---|---|---|---|
| 0 | `KIND_V2` | 恒定乘积（Uniswap V2、Sushi 及其分叉） | 基于 `getReserves` 的闭式 `outV2` | 储备 · 可验证交易对 | 90,000 |
| 1 | `KIND_V3` | 集中流动性（Uniswap V3 及 V3 型分叉） | 基于 `slot0` 的闭式 `outV3` | 集中于池地址 · 可验证交易对 | 110,000 |
| 4 | `KIND_V4` | Uniswap V4 单例合约 | 基于 `extsload` 的闭式 `outV3` | 集中于单例合约 | 180,000 |
| 5 | `KIND_SOLIDLY` | Solidly（Aerodrome、Velodrome 及其分叉），stable 与 volatile | 询问池子 `getAmountOut`；以复制的曲线作为后备 | 储备 · 可验证交易对 | 90,000 |
| 6 | `KIND_ALGEBRA` | Algebra（Camelot 类），动态费用 | 基于 `globalState` 的闭式 `outV3` | 集中于池地址 · 可验证交易对 | 110,000 |
| 8 | `KIND_V4_NATIVE` | 持有链原生货币的 V4 池 | 与类型 4 相同的定价方式 | 集中于单例合约 | 215,000 |

六种类型，四个实际工作的族：恒定乘积 {0}、集中流动性 {1, 6}、Solidly {5}，以及 V4 单例合约 {4, 8}。属性列不是描述性文字：它是 Core 中的位表 `THETA_ATTR = 0x040A9400A9`，每种类型四位——*读取储备*、*集中于池地址*、*集中于单例合约*、*暴露 `token0()`/`token1()`*——因此五个合约中的每个成员归属问题（“这种类型读取储备吗？”）都是一次移位加一次 AND（`kindHas`、`kindHasAny`），而没有任何位的类型会失败即关闭，不存在任何人可能遗忘的默认代码分支。gas 列是第二张表 `THETA_GAS`，只由 Solver 的 `estGas` 读取，单位为每条分支 5,000 gas。

**类型 2、3 和 7 因刻意切除而缺席。** 加权族（3）从未产生过可路由的报价。两个 Curve 族（2、7）能够工作，但仍在 2026 年八月的信任边界加固中被移除，因为支持它们需要 Router 唯一的代币 `approve`、唯一由调用者证明而非从池子实测的深度数字，以及 Hub 交易对真实性证明中唯一的例外——三个攻击面，每一个都是其类别中的最后一个。退役的编号永不重新分配：`decodeKind` 从 Monoslot 位中读取类型，因此重用 2 会重新解释所有曾以它记录的池子，而且一旦被切除的符号重新出现，CI 守卫会让构建失败。

**原生货币类型（8）之所以存在，是因为有一个不变量恰在那里被打破，且只在那里。** Router 的工作假设——每种资产都是带有 `balanceOf` 的 ERC-20——恰好在 V4 池的货币是链的原生资产时失效，而把这个例外编码为一种*类型*，使它在池子记录中可见、在路由计划中携带，并且审计者可以 grep 到。定价不需要代码分支：池 ID 由两种排序后的货币推导，而 `address(0)` 按构造必然排在最前。这种类型凭经验赢得了它的位置：2026-08-13 在所服务的各条链上测量，V4 内以 ETH 计价的流动性中有 62.9 % 位于原生池（Arbitrum 99.6 %、Optimism 95.0 %、Base 48.9 %）。

### §4.2 闭式解

**恒定乘积。** 储备满足 $x \cdot y = k$，以基点表示的费用 $f$ 从输入中扣除。Core 计算

$$
y \;=\; \mathrm{outV2}(x,\, r_{\mathrm{in}},\, r_{\mathrm{out}},\, f) \;=\; \left\lfloor \frac{x\,(\mathrm{BPS}-f)\; r_{\mathrm{out}}}{\,r_{\mathrm{in}}\cdot \mathrm{BPS} \;+\; x\,(\mathrm{BPS}-f)\,} \right\rfloor
$$
^e2

直到最后一步才做除法，因此唯一的舍入是最后一个商的向下取整；费用达到或超过 `BPS` 会使池子无法报价（返回零）。进入该公式的费用是 `effV2Fee(declared)`：声明费用为零或高于 `V2_FEE_CEILING_BPS = 100` 时，会被替换为标准的 30 bps，因此注册无法通过声明一个不合理的费用来压低自己的报价——以及该报价所锚定的底线；同一规则在执行路径上镜像实施，因此交易双方以同一个数字定价。

**算例 1——恒定乘积报价。** 一个池子以标准的 30 bps 持有 $r_{\mathrm{in}} = 1{,}000{,}000$ USDC 和 $r_{\mathrm{out}} = 500$ WETH；交易者卖出 $x = 10{,}000$ USDC。以池子自身的单位计（USDC 有 6 位小数，WETH 有 18 位），$x = 10^{10}$，$r_{\mathrm{in}} = 10^{12}$，$r_{\mathrm{out}} = 5 \times 10^{20}$：

1. 扣费后的输入：$x(\mathrm{BPS}-f) = 10^{10} \times 9{,}970 = 9.97 \times 10^{13}$。
2. 分子：$9.97 \times 10^{13} \times 5 \times 10^{20} = 4.985 \times 10^{34}$。
3. 分母：$10^{12} \times 10^{4} + 9.97 \times 10^{13} = 1.00997 \times 10^{16}$。
4. 输出：$\lfloor 4.985 \times 10^{34} / 1.00997 \times 10^{16} \rfloor = 4.935790 \times 10^{18}$ wei，即 **4.935790 WETH**（保留六位小数；合约将最后一个商向下取整到 wei）。

按每 USDC 0.0005 WETH 的现货价格，同样的 10,000 USDC 可换得 5 WETH；成交价比现货低 1.28 %，其中 0.30 % 是费用。Core 对这条分支基于储备的冲击度量是 $\mathrm{impactV2Bps} = \lceil x \cdot \mathrm{BPS} / (r_{\mathrm{in}} + x) \rceil = \lceil 10^{14} / 1.01 \times 10^{12} \rceil = 100$ bps——即 §11 中 Iron-Law 底线所使用的数字。

**集中流动性。** V3 型池子不存储储备；它们存储 Q64.96 定点格式的平方根价格 $\sqrt{P}$ 和活跃流动性 $L$。在一个 tick 内，对于 token0 → token1，费用 $f$ 以百万分之一计，且 $x_{f} = \lfloor x\,(10^{6} - f)/10^{6} \rfloor$：

$$
\sqrt{P}\,' \;=\; \frac{L\,\sqrt{P}}{\,L \;+\; x_{f}\,\sqrt{P}/Q_{96}\,},
\qquad
y \;=\; \frac{L\left(\sqrt{P}-\sqrt{P}\,'\right)}{Q_{96}}
$$
^e3

而对于 token1 → token0，$\sqrt{P}\,' = \sqrt{P} + x_{f} Q_{96}/L$ 且 $y = L\,Q_{96}(\sqrt{P}\,' - \sqrt{P})/(\sqrt{P}\,\sqrt{P}\,')$，除法分两个阶段进行。朴素的计算会溢出：$L \cdot \sqrt{P}$ 可达 $2^{288}$。Core 从不构造这个乘积——每个乘积都经由全精度的 `mulDiv`（512 位中间值、256 位结果）分解，因此每个阶段都可证明不会溢出；而一个会把价格往错误方向移动或移到零的步骤返回零，而不是一个数字。Algebra 池（类型 6）共用这一代码分支，只在一个方面不同，而该代码分支能处理它：它们的状态与动态费用位于 `globalState` 中，只读取一次（§5.4）。

该公式在单个 tick 内是精确的，跨越 tick 边界时则不精确，此时单 tick 形式会高估。调度器不复制跨 tick 的算术：复制交易场所的内部数学是一种结构性负担，因为副本与原版之间的任何偏差都会表现为错误定价的报价。取而代之的是两样东西。Core 带有一个边界钳制（`sqrtBoundary`），在当前区间的边缘截断该步——对落在区间内的部分精确，对其余部分严格偏低，绝不偏高——设计把它放在*承诺*一侧，而不是排序一侧，因为只对有 tick 的族做钳制，会让交易场所在两种约定下被比较。在本文所测量的代码树中，该钳制已定义但尚未接入：`Router._v4LegQuote` 和 Core 的排序代码分支都调用未钳制的单 tick 形式，因此离开其区间的集中流动性分支只受 §11.3 的逐分支底线和跳预算约束，并以 Iron-Law 底线作为最后防线。而在执行时，Iron-Law 底线是对照 Router 根据实际到达数量在帧内重新推导的报价来强制执行的，因此 tick 边界处的高估让路由付出的是排序准确性，绝不会让用户失去底线。当集成方需要池子自身的数字时，Quoter 的 Exact Pass（§12）会提供它。

**深度。** 每个代码分支还返回一个以代币单位计的深度——对储备族是较短的储备一侧（`shortSide18`），对集中流动性族则是 $L$ 在当前价格下所代表的虚拟储备 $L/\sqrt{P}$ 或 $L\sqrt{P}$（`depthFromL18`），因此深度相等的 V3 池与 V2 池在分配器中比较时相等，而不会相差 $\sqrt{P}$ 倍。

### §4.3 两种费用单位，以原生形式携带

恒定乘积与 Solidly 交易场所以基点报价费用；集中流动性交易场所以百万分之一报价费用。调度器以各自的原生单位携带它们，从不相互换算，以两个常量而非一个的代价消除了一类舍入故障。有两个交易场所族只在执行时才知道自己的费用——V4 动态费用池和 Algebra——两者都通过从提供价格的同一次状态读取中测量费用来处理（§5.4）。

### §4.4 一个调度器，两个界面

| 类型 | Quoter 预览 | 帧内（Solver 的计划；Router 的重新推导） |
|---|---|---|
| V2 (0) | 闭式 `outV2` | 闭式 `outV2` |
| V3 / Algebra (1, 6) | 基于 `slot0` / `globalState` 的闭式 `outV3`；Algebra 的实时费用从同一次读取中测量 | 相同 |
| Solidly (5) | 询问池子；以复制的曲线 × 9,800 / 10,000 作为后备 | 相同 |
| V4 / V4 原生 (4, 8) | 经由 `extsload` 的闭式 `outV3`，失败即关闭的费用闸门（E19） | 相同 |

因此，区分预览与成交的是时间：在预览区块与执行帧之间发生变化的状态。§12 正是在 240 个样本上测量了这一差距。

## §5 Uniswap V4 端到端

Uniswap V4 并不是一种新的池合约，而是一种新形态的交易场所，它推翻了 2020 至 2024 年间构建的每一个路由器所依赖的四个假设。池子没有地址——它们是某个单例合约（singleton）存储中的条目，以哈希为键。任意代码在兑换内部运行——钩子（hook）在路由器正在执行的结算中的既定节点上执行。费用不必是常数。池子还可以持有链的原生货币，而原生货币没有 `balanceOf`。本节从结构上回应全部四点，使 V4 分支——对 Solver、对底线、对交易者而言——与任何其他分支毫无区别。

### §5.1 定位一个没有地址的池子：先推导，再证明

确定性推导 𝒟 计算地址（§7），但 V4 池没有可计算的地址。它拥有的是一个标识符——其 `PoolKey` 的 keccak 哈希——因此推导表的模式 9 推导的是 *poolId* 而非地址，然后做一件任何地址推导都做不到的事：它证明池子存在，方法是读取 PoolManager 自身存储中该 id 对应的数据，并要求平方根价格非零、流动性非零。没有人能伪造这一证明，因为除了管理器之外，没有人能写入那段存储。伪造的 id 解析为零，随即被丢弃。

**算例 4——由键得到 V4 池标识符。** 规范 id 为 $\mathrm{poolId} = \mathrm{keccak256}(\mathrm{abi.encode}(c_{0}, c_{1}, \mathrm{fee}, \mathrm{tickSpacing}, \mathrm{hooks}))$（`computeV4PoolId`），共五个 32 字节字。以 Base 上 0.05 % 费率档的原生 ETH / USDC 池为例：$c_{0} = \mathtt{0x0000…0000}$（原生货币排在前面），$c_{1} = \mathtt{0x833589fCD6eDb6E08f4c7C32D4f71b54bdA02913}$（USDC），fee $= 500$，tickSpacing $= 10$，hooks $= \mathtt{0x0}$。

1. `abi.encode` 排布出 160 字节：两种货币各自左填充至 32 字节，然后是 `500`，然后是 `10`（一个 `int24`，符号扩展至 32 字节），最后是零钩子。
2. $\mathrm{poolId} = \mathtt{0x96d4b53a38337a5733179751781178a2613306063c511b78cd02684739288c0a}$。
3. 注册表中 V4 行的 `pool` 字段是该 id 的低 160 位，$\mathtt{0x781178a2613306063c511b78cd02684739288c0a}$——一个没有代码的地址，这就是为什么 V4 行从不被调用 `token0()`、从不被读取余额，而是通过重新推导来证明自身（§9）。
4. 池子的存储基址为 $\mathrm{keccak256}(\mathrm{abi.encode}(\mathrm{poolId}, 6)) = \mathtt{0x13a3a697…73b2893d}$：管理器的槽 6 是 `pools` 映射。Core 读取该槽处的字 0 和 $\mathrm{base} + 3$ 处的字 3（`v4SqrtAndLiq`，选择器 `extsload(bytes32)` = `0x1e2eaeaf`）。
5. 字 0 在位 [0, 160) 中打包 $\sqrt{P}$，在 [160, 184) 中打包 tick，在 [184, 208) 中打包协议费，在 [208, 232) 中打包 LP 费；字 3 的低 128 位承载活跃流动性。若 $\sqrt{P}$ 或 $L$ 任一为零，则该池对本协议而言不存在。

同一交易对的包装版本——$c_{0} = \mathtt{0x4200…0006}$（WETH），同一费率档——的 id 为 $\mathtt{0x90333bb0…ebd943a0}$：这是另一个深度不同的池子，这也是扫描为何同时探测两个键、且先探测原生键的原因（见下文）。第 5 步中的布局并非取自文档：在主网分叉上，通过该布局读取的同一个池子与通过规范 `StateView` 合约读取的结果数值相同，而 Core 的注释所引用的正是这一恒等关系。

**成本阶梯。** 产生候选 id 的扫描是一架阶梯，最便宜的一级在前，因为对每种费率与间距组合的朴素遍历，会在求解路径上产生无法接受的 gas 账单：

| 级 | 尝试内容 | 命中时的成本 |
|---|---|---|
| 1 | 已为该代币对学到的费率档模式 | 一次探测——稳态路径 |
| 2 | 在为冷扫描付费之前做一次来源检查 | 一次读取 |
| 3 | Uniswap 规范费率档，通过 `extsload(bytes32[])` 批量读取 | 整批一次调用 |
| 4 | 注册行声明的 `(fee, spacing)` 组合 | 以注册内容为界 |
| 5 | 冷启动生成网格——fee $= 10{,}000\,j$，spacing $= 100\,j$，$j$ 从 `V4_GRID_MAX = 99` 递减 | 至多探测 `V4_GRID_PROBES = 40` 次 |

整个扫描在得到 `V4_CAP = 8` 个已证明的池子时停止。有两个性质源自构造本身而非某项检查：带钩子的池子永远不会被此扫描输出——它推导的是*无钩子*的 id，而带钩子池子的无钩子 id 在管理器中并不存在，因此在任何策略问题被提出之前，它就无法通过存活证明；来自不同费率档猜测的重复 id 合并为一个候选，因此一个池子无法通过别名占满漏斗。探测顺序本身就是一种策略，因为上限会被最先探测的对象消耗：与链原生资产组成的交易对在 V4 中有两个键，原生键与包装键，而在确定该顺序时，经测量原生键在所服务的链上更深（Base 上为 3.76×，Robinhood Chain 上为 292×），所以先探测它。

![FIG-2 — V4 推导并证明的阶梯：从已学到的费率档模式到有界生成网格共五级，每个候选 id 都先在管理器存储上被证明存活，才计入八个的上限；带钩子的 id 在这条路径上永不存在。](https://blazephoenix.xyz/whitepaper/figs/zh/fig-2.png)

**无许可之门。** 任何人都可以调用 `claimV4(c0, c1, fee, tickSpacing)`，让一个无钩子的池子被接纳，因为该声明自带证明：id 由提交的键重新计算，并从管理器存储中读回，因此虚假声明解析为零，什么也不会被接纳（`HubE(9)`）。另有三个条件把守此门：交易对的一侧必须是可路由的桥接币，这样有上限的注册表中的席位绝不会浪费在路由器永远无法穿越的交易对上；有效费用必须能在下文的费用闸门下报价；该声明还必须通过与兑换驱动的注册相同的接纳余量（§9），并以池子的实测流动性作为其深度。公众可以教注册表，却无法欺骗它。

### §5.2 读取一个不应答任何调用的池子

一旦 id 被证明存活，调度器就需要价格和流动性——而这里没有可调用的 `slot0()`。Core 如上例所示，通过 `extsload` 直接读取单例合约的存储，而 V4 分支归约为 §4.2 的集中流动性闭式解：同样的数学，同样的溢出纪律。单例合约改变的是状态存放的位置，而不是状态的含义。无代码或不合规的管理器会产出全零的字——失败即关闭，从不回滚。

### §5.3 通过单例合约结算

执行颠倒了通常的控制流。路由器不是调用池子、再被回调以付款，而是对管理器调用 `unlock`，并在管理器授予它的回调内完成整笔兑换：兑换，然后通过 `sync → settle → take` 结清每一种欠付货币，然后释放锁。在途货币通过瞬态存储（`TSLOT_V4IN`、`TSLOT_V4OUT`）跨越 unlock 边界传递，因此该帧不会弄脏任何持久状态，且兑换之间的上下文可证明为空。管理器返回的 `BalanceDelta` 是打包的——`amount0` 在高 128 位，`amount1` 在低位——Router 在任何结算算术运行之前按此解码。

原生货币保持着真正重要的不变量。Router 处处以 WETH 为规范——进入 `swapExactInNative` 的原生价值在入口处恰好包装一次，而原生输出被刻意不予实现：接收方收到 WETH，没有任何路径能将其悄然困住。原生 V4 分支在其自身的 unlock 帧内*即时*解包——`WETH.withdraw`，然后带值 `settle`，从原生 `take` 收到的 ETH 在同一帧内重新包装——因此原生 ETH 从不以静止状态存在于合约中。为此所需的唯一新增接口是一个按需求所允许的最窄范围设限的 `receive()`：一个瞬态槽（`TSLOT_ETHOK`）保存当下唯一被允许向 Router 发送原始 ETH 的地址——解包期间是规范 WETH 合约，原生 take 期间是 PoolManager，其他任何时刻为零——因此来自其他任何人的裸 ETH 都会回滚。在 `weth` 接线之前，原生之门处于失败即关闭状态（`RouterE(3)`）。

### §5.4 只在执行时才存在的费用

静态费率的 V4 池在其键中携带 LP 费，且不可变。池管理器还可能额外收取 Uniswap 自己的管理器费——每个方向上限 1,000 pips，即千分之一——而 Core 的静态分支并不计入它，因此一旦 Uniswap 的费用控制器启用该费用，基于静态键的报价可能把交付输出高估至多该管理器费（撰写本文时，它在所服务的每条链上均为零）；差额落在底线之内，而费用基数因为是实测的，会忽略它。动态费率的池子则携带哨兵值 `0x800000`，其真实费用存放在 `slot0` 中。按面值报价该哨兵值，会把交易定价为免费，而执行时却支付实时费率。闸门在 Core 中只有三行（`effV4Fee`）：

$$
f_{\mathrm{eff}} \;=\; \begin{cases} f_{\mathrm{key}} & f_{\mathrm{key}} \ne \mathtt{0x800000} \\ \mathtt{0xFFFFFF}\ (\text{unquotable}) & f_{\mathrm{key}} = \mathtt{0x800000} \ \wedge\ f_{\mathrm{proto}} \ne 0 \\ f_{\mathrm{LP}}\ \text{read from } \mathtt{slot0} & \text{otherwise} \end{cases}
$$
^e19

伴随非零协议费的动态费率键返回大于或等于 $10^{6}$ 的费用，而 `outV3` 对其返回零：失败即关闭，因为协议费与 LP 费的组合方式尚未锚定到令我们满意的程度，且撰写本文时 Base 上实测的协议费为零，所以该分支在实践中没有任何代价。同一规则在相邻的一族中封闭了同样的接缝：Algebra 池按构造就是动态费率，注册时使用零哨兵，因此 `quoteV3Fee` 以非零的配置费用为准，对动态池取自已提供其价格的 `globalState` 读取，而对费用以 tick 间距为键并存放在池上的集中流动性分叉，则取池子自身的 `fee()`，在无人应答时以 `0xFFFFFF` 失败即关闭。静态 V3 池不需要额外读取，报价逐字节一致。

还剩一道接缝，它被限定而非消除：动态费率钩子可以在 `beforeSwap` 内逐笔覆盖其费用，因此 `slot0` 中存储的费用并非在所有情况下都是实际执行的费用。这一残余由 Hub 在接纳时的钩子允许列表，以及在执行时由实际输出重新推导的 Iron-Law 底线所约束，因此恶意覆盖的结果是回滚或底线之内的差额，绝不会是低于底线的成交（§14）。

### §5.5 钩子：以算术筛查，绝不靠询问

钩子是在 Router 正在执行的结算内部运行的任意代码。直觉上的防御——询问钩子打算做什么——并不是防御，因为恶意钩子会撒谎或重入。BlazePhoenix 从不向钩子询问任何事。取而代之的是三道相互独立的防线，最便宜的在前，§14 将展开论述：钩子的权限位位于其自身地址的低十四位，在部署时即已固定，而允许修改兑换差额的两个位，会在任何代币移动之前被一次 AND 拒绝（`hookAltersDeltas`、`RouterE(9)`）；钩子只有在处于允许列表中、且其运行时代码仍与接纳时固定的 codehash 相符时才可路由（`isHookLive`）；投影算子 Ξ 在排序之前将修改差额的钩子从 Solver 的候选集中移除，因此这样的路由甚至无法被表示。残余风险与机制一并说明：一个在允许列表中、不修改差额的钩子仍可能在兑换中途回滚，浪费尝试所耗的 gas——这是出于原则拒绝调用不可信代码来探查它本会做什么所付出的代价。

### §5.6 这一集成的价值

上述每一种机制，要么是已在别处使用、应用于新状态布局的 Core 原语，要么是可推广到 V4 之外的真正新原语——存在性证明式发现。没有任何一项是逐池集成，也没有任何一项是需要人工维护更新的策展列表。V4 池无需目录即可被发现，在无人能写入的存储上得到证明，以与其他所有集中流动性场所相同的闭式解定价，通过实测进行费用把关、并在测量不精确时以失败即关闭的方式拒绝，借助不可变的地址算术筛查恶意钩子，通过单例合约自身的锁协议结算，并且可以用原生 ETH 访问，而 Router 从不以静止状态持有哪怕一 wei。§17 给出测量结果：在 Arbitrum 上的工厂普查中，V4 族赢得的跳对多于任何其他已注册交易场所；在 Optimism 上，普查记录了据我们所知该链上首次经 V4 路由的聚合交易。据我们所知，没有其他公开的聚合器能够完全在执行交易内部推导、证明、定价、筛查并结算 V4 池（包括原生 ETH），且不依赖任何策展池列表；如果您找到了一个，那么这一说法就是错的，我们也很想知道。

## §6 Solidly 求解器

有些不变量没有足够简单、能够安全复现的闭式解，而复现它们恰恰是协议在其他地方所拒绝的复制风险。对于这类交易场所，调度器通过场所暴露的最窄的诚实通道去询问池子——并为不应答的分叉保留一个副本作为后备。

Solidly 族——Aerodrome、Velodrome 及其分叉——以四次不变量服务于稳定交易对上的相关资产，该不变量比常数乘积更紧密地贴合对角线，同时仍允许偏离：

$$
k(x, y) \;=\; x^{3}y \;+\; x\,y^{3} \;=\; x\,y\left(x^{2}+y^{2}\right)
$$
^e5

在平衡点附近，这条曲线几乎把全部输入作为输出交付——在稳定币与流动性质押流量聚集之处，滑点恰好最小。Solidly 的波动交易对是常数乘积，而 Core 的波动分支*就是* `outV2`——单一生产者，由蜕变关系 MR7 固定（§15）。

![FIG-3 — 平衡稳定交易对的输出对输入曲线：Solidly 四次曲线与常数乘积及零滑点对角线的对比，均取自 Core 自身的公式。](https://blazephoenix.xyz/whitepaper/figs/zh/fig-3.png)

**主路径：询问池子。** `getAmountOut(amountIn, tokenIn)` 由交易对自身的字节码计算——包括实时费用、曲线与舍入——因此恰好请求该数值的兑换按构造即可满足池子的不变量检查，无需任何余量。触发后备的条件是应答至多为 1 wei；在一个恰好应答 1 的池子曾让三个询问通道（Solver、Router、Quoter）中的两个走向不同分支之后，这一条件在三者间得到了统一。

**后备：复制，然后少要。** 当某个分叉未暴露该选择器时，调度器从交易对的工厂读取实时费用（`getFee(pool, stable)`；声明的后备费用只有在与 V2 分支相同的 100 bps 上限之内才被采信，否则取 30 bps），在按小数位归一化的储备上求解不变量，并将结果乘以 9,800 / 10,000——200 bps 的折扣，使副本无法观察到的池子舍入始终有余地。该折扣仅在后备路径上施加，池子亲自应答时绝不施加。

**求解。** 给定交易后的输入余额 $x$ 以及由交易前储备得到的目标不变量 $K$，Core 求 $f(y) = x^{3}y + xy^{3} - K$ 的根，其中 $f'(y) = x(x^{2} + 3y^{2}) > 0$，采用以 $y_{0} = Y$（交易前的对侧储备）为初值的牛顿迭代（`_solY`）：

$$
k(x, y_{n}) < K:\ \ y_{n+1} = y_{n} + \max\!\left(1,\ \left\lfloor \tfrac{K - k(x,y_{n})}{f'(y_{n})} \right\rfloor\right); \qquad
k(x, y_{n}) \ge K:\ \ y_{n+1} = y_{n} - \delta_{n},\ \ \delta_{n} = \begin{cases} \lfloor y_{n}/2 \rfloor & d_{n} \ge y_{n} \\ \max(1, d_{n}) & \text{otherwise} \end{cases},\ \ d_{n} = \left\lfloor \tfrac{k(x,y_{n}) - K}{f'(y_{n})} \right\rfloor
$$
^e6

看似自然的初值——常数和近似——是错误的，而且会悄无声息地破坏价格：对于吸收数倍于其储备的输入的池子，它会落在远高于根的位置，处于 $f$ 极其陡峭的区域，步长向下取整为零，求解器便停在一个自信、可信却错误的数值上。以对侧储备为初值并双向步进，对平衡池与高度倾斜的池都能收敛。会越过零的向下步长被替换为当前迭代值的一半；每一步至少强制前进一个单位；当相邻迭代值相差至多一个单位时迭代退出，并通过最后一次不利于吃单方的单位调整落在不变量安全的一侧。循环上限为 64 次迭代，且上限失败即关闭：求解器返回初值本身，调用方的 $y \ge Y$ 守卫将其映射为零报价——池子被视为无法定价，这与 Aerodrome 自身宁可拒绝也不错误定价的做法一致。导数趋于零时走同一出口。

**小数位归一化。** 该不变量是四次齐次的，因此当两种代币小数位相同时，尺度相互抵消，原始储备可直接使用。像 DOLA（18 位小数）对 USDC（6 位）这样的交易对会把不匹配带入四次式，因此 Core 在求解前把两侧缩放到共同的 $10^{18}$ 基准，求解后再反缩放：

$$
X = r_{\mathrm{in}}\cdot 10^{\,18-d_{\mathrm{in}}},\quad Y = r_{\mathrm{out}}\cdot 10^{\,18-d_{\mathrm{out}}},\quad A = \left\lfloor\frac{x\cdot 10^{\,18-d_{\mathrm{in}}}\,(\mathrm{BPS}-f)}{\mathrm{BPS}}\right\rfloor,\quad \mathrm{out} = \left\lfloor\frac{Y - y^{\star}(X+A,\,K)}{10^{\,18-d_{\mathrm{out}}}}\right\rfloor
$$
^e7

报告超过十八位小数的代币报价为零，而不是让缩放下溢。另一种代币的小数位从池子读取，而不是取自调用方——一个接受调用方坐标的单一生产者原语，会重新打开它本为封闭而存在的分歧。

**在整个定义域上失败即关闭。** 四个守卫决定是否对曲线求值，每个都返回零而不回滚，因为报价内部的回滚意味着库 `DELEGATECALL` 解开 Solver 针对该交易对的整个计划：$X$ 与 $Y$ 不得超过 $3.4 \times 10^{38}$；$X + A$ 同样不得超过；`_solKFits` 要求不变量 $k = xy(x^{2}+y^{2})/\mathrm{WAD}^{3}$ 与导数 $x(x^{2}+3y^{2})/\mathrm{WAD}^{2}$ 在初值处都能放入 256 位字，而初值是牛顿迭代访问的最大点。最后这项检验不使用除法——它计算 512 位乘积的高位字并与一个 WAD 比较（`_mulFitsWad`）——因为早先的形式 $a \le \max \cdot \mathrm{WAD} / b$ 本身就在持有不到一个单位代币的池子上溢出。§15 的 N 版本通道于 2026-09-05 发现了这一漏洞；修复比被替换的代码小 35 字节，并以先红后绿的方式合入，配有覆盖全定义域的 5,000 次模糊测试、在 Python 中对同一算术进行的 60,000 个样本扫描，以及守卫中的三个变异体。

**实测残差与 200 bps 余量。** 以池子自身的 `getAmountOut` 为基准真值，将副本与实时 Aerodrome 池进行了对比测量：

| 池 | 状态 | 基准真值 | Core 输出 | 偏差 |
|---|---|---|---|---|
| USDC / USDbC | 平衡（6 / 6 位小数） | 999,534,071 | 999,534,071 | 0.000 % |
| DOLA / USDC | 倾斜（18 / 6 位小数） | 985,528,437 | 987,998,286 | 0.251 % |
| USDz / USDC | 倾斜（18 / 6 位小数） | 899,325,141 | 901,565,830 | 0.249 % |

平衡交易对精确到整数一致；倾斜交易对位于 0.5 % 以内，且偏高，因为池子扣费后的余额舍入从外部不可见。这一残差正是后备路径少要 200 bps 的原因：该余量保证交易对的不变量检查在执行时有余地，把可能因报价过高导致的回滚转化为确定的成交，并且它在预览与帧内两个界面上以完全相同的方式施加，使二者保持同步。§15 的规范预言机（oracle）通道独立地界定了这条曲线：与依据交易场所规范编写的实现相比，Core 的稳定报价在 5,000 个模糊输入上偏差不超过 4 wei。

## §7 确定性推导 𝒟

池子必须先被找到，才能被报价。业界的答案是询问：调用交易场所的工厂，读取一个存储映射并返回地址，调用方采信工厂的说法。BlazePhoenix 支持这一答案——四种工厂调用模式覆盖那些部署不可复现的交易场所——但只要算术允许，就优先采用更强的答案：计算地址，不做任何外部调用。计算出的地址可由任何持有同样三个输入的人验证；获取来的地址只能被信任。

其机制是 CREATE2。EVM 让合约地址成为其部署者、盐值和其 init code 哈希的纯函数：

$$
\mathrm{pool} \;=\; \mathrm{addr}_{20}\!\left(\mathrm{keccak256}(\mathtt{0xff}\,\Vert\,\mathrm{origin}\,\Vert\,\mathrm{salt}\,\Vert\,\mathrm{initCodeHash})\right)
$$
^e8

其中 $\mathrm{addr}_{20}$ 取哈希的最后二十个字节。Core 只在一处完整写出这 85 字节的原像（`create2Address`）；`deriveAddress` 根据模式选择盐值多项式和来源地址，Hub 经证明的 Algebra 推导也复用同一个生产者。

| 模式 | 族 | 解析方式 | 盐值 / 探测细节 |
|---|---|---|---|
| 0 | V2 | 工厂调用 `getPair(t0,t1)`——选择器 `0xe6a43905` | — |
| 1 | V3 / Algebra | 工厂调用 `getPool(t0,t1,fee)`——`0x1698ee82`；未命中时，`poolByPair(t0,t1)`——`0xd9a641e1` | — |
| 2 | Solidly | 工厂调用 `getPool(t0,t1,stable)`——`0x79bc57d5` | — |
| 3 | 集中流动性 Solidly 分叉（Slipstream、Velodrome CL） | 工厂调用 `getPool(t0,t1,tickSpacing)`——`0x28af8d0b` | — |
| 4 | V2 CREATE2 | 纯算术 | `keccak256(packed(t0,t1))`，origin = 工厂 |
| 5 | V3 CREATE2 | 纯算术 | `keccak256(encode(t0,t1,fee))`；`fee == 0` 是 Algebra 哨兵值 → `keccak256(encode(t0,t1))`，origin = 工厂的 `poolDeployer()`（`0x3119049a`），在接纳时经证明 |
| 6 | Solidly 克隆 CREATE2 | 纯算术 | `keccak256(packed(t0,t1,stable))`，origin = 工厂 |
| 7 | CL CREATE2 | 纯算术 | `keccak256(encode(t0,t1,tickSpacing))`，origin = 工厂 |
| 8 | *已退役* | 因 Curve 移除而释放；一块墓碑——`MODES_VALID = 0x2FF` 拒绝它 | — |
| 9 | V4 推导扫描 | 推导无钩子的 poolId，并在 PoolManager 上证明其存活（§5.1） | 网格 ≤ 99 档，冷探测 ≤ 40 次，达到 8 个池即停止 |

模式 0–3 各为一次 `staticcall`；模式 4–7 不做任何调用，只需正确的 init-code 哈希；模式 9 服务于那个两种方式都无法定位其池子的族。

**定理、声明与证明。** 推导出的地址是关于交易对的一条定理：给定来源地址、盐值多项式和 init-code 哈希，地址仅凭 keccak 即可得出，任何有异议的人都能重新计算。询问得来的地址是工厂对其自身存储的声明——而工厂可能用一个其他代币的池子来应答。自 2026-09 起，询问得来的池子（模式 0–3）在发现过程将其列出之前，必须证明自身的交易对：Hub 读取其 `token0()` 和 `token1()`——与 Router 在付款接缝处所做的两次读取相同——不匹配则丢弃该候选，因此执行器会拒绝的池子永远不会被列出、规划或排序。促成这一改变的是 §15 的恶意交易场所矩阵：它的首次运行列出了一个由策展人接纳的工厂所应答的池子，规划器对其排了序，而执行器在付款接缝处拒绝了它——资金从未面临风险，但该交易对被拒绝，而冒名者却赢得了拆分。

**V3 形态行中的两个微妙之处。** Algebra（Camelot 类）收取动态费用，因此费用永远不能成为其身份的一部分：Algebra 注册声明费用为零作为哨兵值，模式 5 从盐值中去掉费用，而 CREATE2 来源地址是 Algebra 工厂暴露的独立 `poolDeployer` 合约。这个来源地址是工厂在接纳之后仍可操纵的唯一推导输入——代理合约可以在 codehash 不变的情况下改变其应答——因此 Hub 在 `addFactory` 时对其进行一次证明（`factoryDeployer`），此后都从经证明的来源地址推导；控制权放弃之后，该证明即被冻结。在工厂调用一侧，Algebra 工厂暴露的是 `poolByPair` 而非 `getPool`，因此一次未返回任何结果的模式 1 查找会在放弃之前改用该选择器重试。

**每次推导都要通过最后一道闸门。** Hub 丢弃任何不携带运行时字节码的推导地址——`extcodesize` 就是全部检查（`hasCode`）——因此错误的 init-code 哈希、过时的注册，或某个族从未部署过的链，产生的是空结果，而不是一个幽灵交易场所。地址上的字节码证明的是存在，而非诚实，这就是为什么在被定位的池子与成交的交易之间，仍然站着接纳、可信带和底线。在多种 `(fee, spacing)` 组合下推导出的同一个池子只列出一次。

**推导与询问之间的边界是经验性的。** 基于克隆的交易场所，如 Velodrome 和 Aerodrome，即使其 init-code 哈希已知，仍停留在工厂调用模式，因为它们的 CREATE2 来源地址位于内部的确定性克隆部署器中，而非工厂——地址无法从公开输入复现，所以协议选择询问。Uniswap V3 是另一方向的旗舰案例：由于到处部署的是同一份池字节码，其 init-code 哈希在每条链上都是同一个常量，并且恒等式 `derived == getPool` 在 Ethereum、Arbitrum、Optimism 和 Base 的分叉上、针对各链自己的工厂均成立（§17）。算术可靠时推导，不可靠时询问，无论哪种都验证一切。

**发现过程逐行消费这张表。** 对于至多 `MAX_FACTORIES = 16` 个已注册工厂中的每一个，Hub 探测每一个声明的 `(fee, spacing)` 组合——Solidly 行的稳定与波动两种风味都探测，V4 行预留至多八个——因此扫描的最坏情况由注册内容固定，而不取决于链的情绪。配置接口在入口处受到把守（§9）：结构上不可能的交易场所无法被存储。

## §8 单槽（Monoslot）

存储是在 EVM 上做任何事情的主要成本：一次冷 `SLOAD` 需要 2,100 gas，若注册表把池子的属性分散在不同槽中，则每评估一条路由、每个池子、每个属性都要再付一次这笔费用。BlazePhoenix 把池子的全部路由状态打包进单个 256 位字——单槽（Monoslot）——只读取一次，并以纯算术解码。

| 位 | 字段 | 宽度 | 含义 |
|---|---|---|---|
| 0 | `active` | 1 | 槽位处于活跃状态 |
| 1–7 | 保留 | 7 | 位 5 = 稳定曲线（注册时从池子自身的 `stable()` 读取）；位 6 = 原生一侧已交换；位 7 原为桥接标志，现已不再写入——桥接加成从交易对实时读取（§9） |
| 8–31 | `fee` | 24 | 费率档，采用交易场所的原生单位 |
| 32–39 | `kind` | 8 | 交易场所类型（§4） |
| 40–47 | `tier` | 8 | 0 = 策展（由运营者预置），2 = 无许可（通过交易学到或经声明获得） |
| 48–59 | `conc` | 12 | 集中度字段，打包前以 `0xFFF` 掩码 |
| 60–63 | `bucket` | 4 | 对数深度桶 |
| 64–95 | `lastUpdateTs` | 32 | 最近一次触及的挂钟时间戳 |
| 96–127 | `emaIn` | 32 | 为输入量 EMA 保留；注册时写为零，已发布的 tick 不更新它 |
| 128–159 | `emaOut` | 32 | 为输出量 EMA 保留；同上 |
| 160–191 | `swapCount` | 32 | 活动计数，在 $2^{32}-1$ 处饱和 |
| 192–223 | `regBlk` | 32 | 注册区块 |
| 224–255 | `lastBlk` | 32 | 最近一次触及的区块 |

![FIG-4 — 单槽位布局：一个 256 位字，十四个具名字段，集中度字段被掩码为十二位，因此永远不会渗入深度桶。](https://blazephoenix.xyz/whitepaper/figs/zh/fig-4.png)

编码是一串移位与 OR 运算（`encodeSlot`）：

$$
s \;=\; a \;\vert\; f\!\ll\!8 \;\vert\; k\!\ll\!32 \;\vert\; r\!\ll\!40 \;\vert\; (c \wedge \mathtt{0xFFF})\!\ll\!48 \;\vert\; b\!\ll\!60 \;\vert\; t\!\ll\!64 \;\vert\; e_{\mathrm{in}}\!\ll\!96 \;\vert\; e_{\mathrm{out}}\!\ll\!128 \;\vert\; n\!\ll\!160 \;\vert\; B_{\mathrm{reg}}\!\ll\!192 \;\vert\; B_{\mathrm{last}}\!\ll\!224
$$
^e9

有一个细节是守卫而非便利：集中度字段在移位*之前*被掩码为十二位，因此永远不会渗入位于位 [63:60] 的深度桶——打包方式从根本上杜绝了那类会破坏打包状态的静默字段重叠，而不是寄希望于调用方保持在范围之内。解码同样机械：每个访问器都是一次移位加一次截断；桶写入器在设置其四个位之前先将其清零；兑换计数饱和而非回绕，因此满载的槽位永远不会把繁忙池子的历史翻转归零。挂钟时间戳由 Hub 在每次 tick 和注册时写入，它同时驱动 §9 的活力衰减和 Solver 的发现新鲜度闸门。

请注意这个字中没有什么：价格。单槽承载为池子排序所需的一切——活动、深度等级、费用、类型、标志、新近度——却不含任何可能被误当作报价的东西，因此注册表的记忆在结构上就无法为交易定价。价格在进行交易的那一帧内，由实时储备重新计算；打包的字只决定哪些池子值得询问。更新路径同样遵循这种节约：经过已知池子的一次兑换只重写该字一次——计数、桶、时间戳，一次 `SSTORE` 加一次 `SLOAD`——因此保持注册表最新的边际成本，搭载在用户本就会发送的交易之中。

为什么一个字如此重要，是一个乘法问题。Solver 在至多三种拓扑中，每个交易对至多探测 `MAX_CANDIDATES = 8` 个交易场所，因此一笔求解完成的交易在移动任何代币之前，可能要为二三十个池子打分。按每个冷槽 2,100 gas 计算，每池五个槽的布局会使这一打分过程耗费数十万 gas；单槽则只需每池读取一次，而 Hub 的 `psisOf` 在一次批量调用中返回所有候选的得分。单槽不是施加在链上路由之上的一项优化；它是链上路由之所以负担得起的根本原因。

## §9 自愈注册表与活力场 Ψ

大多数聚合器之所以知道自己的交易场所，是因为有 keeper 在链下索引池子并把列表推送上链——一个需要信任的流程、一个过期窗口和一项运维依赖，而一个在链上求解路由的协议这三样都不能接受。BlazePhoenix 采取相反的立场：注册表通过交易来学习流动性。

### §9.1 通过交易学习，以及交易对证明

在每一个已执行的分支上，Router 调用 Hub 的 `recordSwap`（`onlyRouter`、`whenLive`），传入池子、其类型、其费率、交易对、金额以及它实测的深度。Hub 首先拒绝 Router 不可能执行的任何类型（`KINDS_EXECUTABLE`）——这是一道本地防线，不依赖 Router 保持部署时的样子——然后走两条路径之一。

已知池子的 Monoslot 被刷新：兑换计数从其*当前已衰减*的基数上增长，深度桶被重新计算，区块号与墙钟时间戳前移——重写一个打包字，没有外部调用。未知池子走冷路径。它必须先通过准入（`_canInsert`，见下文）。然后它必须证明它即将存储的声明：对每一种交易对形态的类型（`KINDS_PAIR_PROOF` = V2、V3、Solidly、Algebra），Hub 读取池子自己的 `token0()` 和 `token1()`，并要求它们与交易对一致——最多两次 `staticcall`，且只在冷路径上。`recordSwap` 的每个参数都是 Router 路由中携带的、由调用者控制的 calldata——池子、类型和深度——因此没有这项证明，攻击者就能以自己挑选的交易对、自己挑选的深度，注册一个自己编写、两种代币都不持有的合约。对于两种 V4 类型，其 `pool` 字段是没有字节码的截断 id，证明方式是重新推导：恢复 tick 间距，重新计算 id 并比对，仅限无 hook 的池子，因此带 hook 的池子永远无法通过这扇门注册；原生 V4 池在 `(address(0), T)` 的两种方向上都会比对。不匹配会*跳过*注册而绝不回滚，因为用户的兑换已经结算，绝不能因注册表的决定而失败。

注册时的交易对证明是 2026 年九月新增的，产生它的测量来自 §15：十五个源码变异被逐一放到每个有状态不变量下运行，而移除这项证明的变异体在第一次运行时挺过了所有测试活动，因为从来没有测试向 Hub 提供过一个交易其他代币的池子。如今 Hub 的测试活动在每次运行中都这样做——交易对反转、共享一个代币、两个都是外来代币——而 `invariant_ActiveEntriesTradeThePair` 读取每个活跃条目的 `token0`/`token1`；该变异体是一个守卫条目，会被它杀死。发现过程对被询问的池子携带同样的证明（§7）。

没有需要运行的索引器，也不存在因为某台服务器宕机而让协议失明的时刻。运营方的 `seedPool` 之门在部署时预先填充交易对（层级 0，经策展），无需许可的 `claimV4` 之门在池子自身的证明下接纳无 hook 的 V4 池（§5.1）；两者都是优化而非依赖——一个空的注册表会通过普通交易自愈成一个已填充的注册表。

### §9.2 得分

活力场 Ψ 将质量与容量分开，只读取 Monoslot 和交易对的实时桥接状态（Core `psi`）：

$$
\Psi(s, t) \;=\; V(s, t)\cdot 2^{\,b(s)} \cdot \left(1 + \tfrac{2{,}500}{10^{4}}\,\mathbf{1}_{\mathrm{bridge}}\right)\cdot\left(1 + \tfrac{500}{10^{4}}\,\mathbf{1}_{\mathrm{conc}}\right)
$$
^e10

深度桶 $b = \min(15, \lfloor \log_{10}(d / 10^{15}) \rfloor)$ 通过其权重 $2^{b}$ 进入：深度每增加一个数量级，权重翻倍，因此深度以亚线性方式计入——深池被明确偏好，但一个仅仅健康的池子不会被巨头抹去。位于桥接交易对上的池子获得 +25 %，因为桥接币是流动性图的结缔组织；集中流动性池再获得 +5 %。桥接加成由单一生产者（`_pairBridged`）从交易对实时读取，而不是取自注册时冻结的某个位；并且在同一交易对内它是统一的，因此永远不会改变同一交易对内池子的排序。

**衰减——唯一的机制。** 活跃度随闲置按一条墙钟规则衰减（`_decayedSwapCount`）：

$$
V(s,t) \;=\; \mathrm{swapCount}(s) \;\gg\; \left\lfloor \frac{t - t_{\mathrm{last}}}{24{,}576\ \mathrm{s}} \right\rfloor, \qquad V = 0 \ \text{once the shift exceeds } 31.
$$
^e11

步长为 `VITALITY_DECAY_STEP_SECONDS = 24,576`——约 6.8 小时——三十二次减半会熄灭任何得分，因此一个沉寂的池子在 786,432 s（约 9.1 天）后归零并完全可被驱逐。一次兑换即可使其复活，而且复活是诚实的：计数从衰减后剩下的值继续，绝不从衰减前的总数继续，因此长时间沉寂后的一笔粉尘兑换无法恢复池子累积的排名。评分器把两种零区分开：*死*槽——空的、从未刷新过的或超出时间视界的——得分真正为零并退出排名；而*活*槽如果只是小计数在移位下被舍入掉，则被抬到下限一，因此一个真实的、最近被触及的池子永远不会因舍入伪影而消失。窗口刻意采用墙钟秒：按区块计数的窗口在每条链上意味着不同的真实时长，而早先一个每 16 个区块移位一次的实现，衰减到零的速度比文档所述快约 128×。

![FIG-5 — 活力衰减：计数 4,096 每 24,576 s 减半，32 步后归零；第 4 天的一次兑换从衰减后的基数复活，而不是从历史总数复活。](https://blazephoenix.xyz/whitepaper/figs/zh/fig-5.png)

### §9.3 驱逐

每个交易对最多容纳 `MAX_SLOTS = 16` 个池子。当第十七个想要进入时，Hub 用完整的 Ψ 为每个现任者打分——包括深度、加成等一切，因此一个深的新来者可以取代一个浅却仍活跃的占位者——并且只有当新来者的预计得分以一定余量超过最弱的现任者时才接纳它（`_canInsert`）：

$$
\Psi_{\mathrm{new}} \;>\; \Psi_{\mathrm{worst}} + \left\lfloor \Psi_{\mathrm{worst}}/4 \right\rfloor, \qquad \Psi_{\mathrm{new}} = 2^{\,b(d_{\mathrm{new}})}
$$
^e13

新来者按保守方式计分——活力为一、使用其自身深度桶、没有加成——深度为零的新来者被直接拒绝。这个余量堵住了一个恶意干扰向量：在简单的“取代最低者”规则下，攻击者可以占住十六个勉强活跃的浅槽，把深的竞争者挡在门外；按 Ψ 排名并加上余量后，真正更深的池子仍然胜出。该常数的局限在强制它的地方写明：新来者的权重是二的幂，而现任者的得分是连续的，因此实际余量从约 100 %（现任者刚好高于一）一直降到约 25 %（现任者为 51，最小可接纳的新来者为 64）；规则的 25 % 同时也是该行为的下限，从不被突破。一个交易频繁的现任者很难被取代，直到衰减发挥作用——闲置两天会让它损失七次减半。无需许可的 V4 认领以池子实测的流动性作为深度，同样要越过这一余量。

### §9.4 发现，及其 gas 旋钮

发现是一个公开的 view：对任意交易对，Hub 遍历其工厂列表，按 §7 的模式推导候选，应用 `hasCode` 和交易对证明，Solver 再将结果与已注册集合合并并按地址去重，因此任何一方都无法压制另一方。为了限制 gas，Solver 应用一道新鲜度闸门（`_registryFresh`）：当该交易对至少有 `MIN_FRESH_VENUES = 3` 个*经策展*的已注册交易场所在 `DISCOVERY_TTL_SECONDS = 3,600` 内被触及过时，它信任注册表并跳过推导扫描。只有经策展的行（层级 0）才能作保：无需许可的行由最先兑换的人写入，而把它计入曾让三个自行注册的粉尘交易对——靠每小时三笔粉尘兑换保持新鲜——为某个交易对关闭发现，并隐藏所有从未注册的诚实交易场所。无需许可的行仍是候选；它不再决定路径。这道闸门是 gas 与覆盖面的旋钮，绝不是安全参数——无论注册表多么陈旧，Iron-Law 底线和用户的最低值都保护每一笔成交，因为两者根本不读取注册表。

### §9.5 配置面

Hub 的注册之门在入口处设防。`addFactory` 在写入任何状态之前拒绝（`HubE(5)`）：`KINDS_ROUTABLE` 之外的类型；`MODES_VALID` 之外的模式；init-code hash 为零的 CREATE2 模式；绑定到 V2 以外类型的 V2-salt 槽；绑定到非 Solidly 类型的 clone 槽；绑定到 V3 或 Algebra 以外类型的 V3-salt 槽，且 Algebra 注册必须把每个费率声明为零哨兵值；以及绑定到 V4 以外类型、或费率与间距列表不配对的 V4 推导扫描行。已知工厂会被就地刷新，绝不会得到第二行，因此一个地址无法耗尽十六个席位（`HubE(4)`）；控制权放弃之后，运行时代码发生变化的工厂无法被重新启用，推导行也无法被转换为询问行。`allowHook` 在准入时锁定 hook 的 codehash，hook 只有在既处于允许列表中*又*未被更改时才可路由（`isHookLive`）；放弃控制权后，移出列表的能力就不复存在，代码变化的 hook 将永远保持暂停。桥接币最多为 `MAX_BRIDGES = 3` 个；`addBridge` 是一项在放弃控制权后仍然存续的策展权力，`removeBridge` 则是一项随之消亡的控制权力。

### §9.6 结构性边界

一句话限定了以上一切：**Ψ 可以隐藏一个交易场所；它永远无法给它错误定价。** 得分对候选集合进行排名和截断——没有任何报价、底线或分配读取它，因为这些都由交易内的实测计算得出；记忆只能以遗漏的方式影响路由选择。无论注册表相信什么，它最坏能呈现的是一个更差但真实的实时价格，而这样的价格所能传递的价值，受可信带、在帧内重新推导的 Iron-Law 底线以及用户设定的最低值三者中最严格者的限制。本金在构造上就无法触及。注册表决定看见什么；它对支付什么没有投票权。

## §10 路由与拆分分配器

恒定乘积池按一条规则定价：它的两份储备相乘之积永远不能缩小。以费率保留系数 $\gamma$（0.30 % 的场所费率意味着 $\gamma = 0.997$）投入 $\Delta$，你得到 $y\,\gamma\Delta / (x + \gamma\Delta)$，你自己的输入就在分母中：你通过一个池子推入的越多，每多一个代币得到的回报就越差。滑点是算术，它的解药也是：把同一笔订单拆分到同一交易对的多个池子上，每个池子被推动得更少。

**算例 2——在两个池子之间拆分。** 一笔 100 的订单面对同一交易对的两个池子，费率均为 0.30 %：池 A 每侧持有 1,000，池 B 每侧持有 4,000。

| 路由 | 算式 | 你得到 |
|---|---|---|
| 全部 100 投入 A | $1{,}000 \times 99.7 / 1{,}099.7$ | 90.661 |
| 全部 100 投入 B | $4{,}000 \times 99.7 / 4{,}099.7$ | 97.275 |
| 20 投入 A，80 投入 B | $1{,}000 \times 19.94 / 1{,}019.94 \;+\; 4{,}000 \times 79.76 / 4{,}079.76$ | $19.550 + 78.201 = 97.751$ |

20 / 80 的拆分是分配器自己的选择，不是猜测：权重与相对于最深候选的实测深度成比例——A 的权重为 10,000 中的 $1{,}000/4{,}000 = 2{,}500$，B 的权重为 10,000——因此 A 承担订单的 $2{,}500 / 12{,}500 = 20$ %。拆分比最佳单一池多出 0.476 个代币，即 48.9 bps。随后拆分闸门询问这一收益是否值得第二个分支：阈值为 $97.275 \times (1 + 25 / 10^{6}) = 97.278$，97.751 越过了它，因此拆分成立。每一行都可以用计算器核对，而且效果是复合的：价格冲击是每个池子对*它自己*那一份的响应，因此路由每增加一个可接纳的分支，每个池子都被推动得更少。

![FIG-6 — 两池示例中输出随发往深池份额的变化：一条在 80 % 附近取最大值的凹曲线，并标出分配器按深度比例给出的点。](https://blazephoenix.xyz/whitepaper/figs/zh/fig-6.png)

### §10.1 路由形态与预算

Solver 构建三种拓扑并返回其中的最大者（`findBestRoutePlan`，次优者作为后备）：一跳的*直接*路由；经过一个中间代币的*桥接*路由；经过两个中间代币的*双桥接*路由——三跳，这是 Solver 构建的最深形态，也是 Router 接受的上限（`MAX_HOPS = 3`）。每一跳在两个刻意分开的预算下拆分为并行分支：`MAX_LEGS_PER_STAGE = 4` 回答*一跳能容纳多少分支*，`MAX_LEGS = 11` 回答*一条路由能容纳多少分支*，两者合起来得到 4、4 + 4 和 4 + 4 + 3——三跳路由的最后一跳得到三个，是因为全局上限挤压了它，而不是因为有人写了特例。桥接币来自 Hub 中由运营方配置的、最多三个代币的集合；Solver 展开每一个已配置的桥接币，并让实测的 `totalOut` 逐笔交易做出决定。实测冲击超过 `MAX_ROUTE_IMPACT_BPS = 9,000` 的路由根本不会被返回，没有可接纳路由的交易对以 `SolverE(5)` 拒绝，而不是编造一条。对任何由调用者提供的路由，Router 执行自己的每跳五个分支上限（`MAX_LEGS_PER_HOP = 5`，`RouterE(3)`）。

### §10.2 漏斗

对每个交易对，Solver 收集已注册的池子，以及——除非注册表是新鲜的（§9.4）——被发现的池子；移除任何 hook 会改动增量的池子（投影算子 Ξ，在此处应用，以使规划之门永远无法组装出 Router 会拒绝的路由）；在一次批量调用中按 Ψ 对并集排名，并保留 `MAX_CANDIDATES = 8` 个——刻意比任何一跳的分支预算更宽，这样排在若干薄交易场所之后的深池会被看到、被加权，并能取代它们，而不会因列表顺序而被饿死。Ψ 完全相等时偏向较低的费率，因此在冷注册表上，漏斗是价格的函数而非历史的函数。

随后每个候选被探测一次，金额为订单的百分之一（`amountIn / 100`，若向下取整为零则用整笔订单），在同一次调用中捕获其边际费率和深度。边际费率干净地分离了全额费率混为一谈的两种信号：价格陈旧的池子无论规模如何边际费率都是错的，而一个小但健康的池子边际费率正确，只是全额输出较差。对于交易对形态的类型，声明的深度以池子实际持有的输出代币数量为上限，因此一个声明 $3 \times 10^{30}$ 却每侧只持有一个代币的合成交易对，会按其实际持有量来衡量。

### §10.3 可信带

在分配之前，候选必须被相信，而相信必须锚定在一个伪造需要代价的量上。可信带的中心是幸存者边际费率的**深度加权中位数**（`_depthWeightedMedian`）：费率连同其深度一起排序，中位数是累计越过一半*深度质量*时的那个费率。它的崩溃点是质量的 50 %——要移动它，攻击者的深度必须超过该交易对一半的真实流动性——而它所加权的深度，对储备池是 `getReserves`，对集中流动性池是活跃流动性，对 V4 是实测流动性：这些都是对池子的简单捐赠无法移动的量。最后这一性质正是锚点不采用最大真实余额的原因：向池子转账会抬高 `balanceOf`，却不移动储备或价格，并且捐赠者可以收回，因此它不是承担风险的资本——一位外部研究者演示了早先的余额锚点被一次捐赠俘获，于是该锚点被替换。边际费率偏离中心超过 `MEDIAN_FILTER_BPS = 500`（±5 %）的候选在发送任何东西之前就被剔除；只有一个候选的集合完全不过滤，而中心舍入为零的集合会退回到普通中位数，这样一个本可路由的跳不会被舍入伪影杀死。这个宽度是经过校准的选择：为流动性质押交易对报价的 Solidly 稳定曲线通常偏离真实费率 20–40 %，会被排除；一个在本次交易规模下读数与中心略有差异的健康池会被接纳。§15 的蜕变测试通道从外部测量了可信带：当一个池子的定价与其同伴相差 $10^{10}$ 时，方案支付的比单独使用该离群池少 35 %——这是中位数拒绝相信它。

### §10.4 分配器及其三道守卫

权重与实测深度成比例，并相对集合中最大的深度归一化（`_weights`）——一次归一化，没有模式，因为每个族的深度都以代币计价（§4.2），因而可以比较。比例分配是对抗性环境下的稳健选择：它不需要迭代，也不需要按场所建立曲率模型，并且避免了均匀拆分会造成的灾难性失败——在一个实测的 WETH/USDC 案例中，在一个 790-WETH 池和一个 0.34-WETH 粉尘池之间按 50 / 50 拆分返回 1,302 USDC，而集中投入深池返回 1,638；按深度加权的分配返回 1,638。当漏斗中的幸存者多于该跳的预算时，保留*按权重*排名靠前、数量等于预算的幸存者，因此一个列得较晚的深池会取代列得较早的薄池。随后，三道守卫立在分配与它所变成的路由之间。

- **容量钳制。** 单 tick 集中流动性公式把当前 tick 的流动性当作覆盖所有价格来建模，因此在薄池上它可能承诺超过池子曾经持有过的数量——在一个观测到的案例中多出 117×。因此，池子形态交易场所（类型 1 和 6）上的集中流动性分支被钳制在池子*实测*的真实输出代币余额的 `MAX_CONC_DRAIN_BPS = 3,000`——30 %。钳制不涉及 V4 分支：单例合约（singleton）把所有池子的代币放在一个余额中，因此 Solver 对类型 4 和 8 跳过这次读取，V4 的承诺除了 §11.3 的底线之外没有物理约束——底线就是它的约束。钳制分两层：当报价超过池子的全部持有量时，承诺在物理上不可能，钳制会按同一比例削减该分支的*承诺输入*，把释放出的输入级联给其余分支，任何无法路由的部分都会被归还给调用者；当成交激进但可能时，只对承诺设上限，因为实测表明在那里削减资本会迫使原本执行良好的池子部分成交。以储备为界的公式不可能过度承诺，不受影响。这道钳制刻意读取 `balanceOf`，而可信带不读：可信带问的是捐赠可以扭曲的*相对*问题，钳制问的是*物理*问题——这个池子付得起吗？——而捐赠确实提高了池子真正能付出的数量。
- **拆分闸门。** 每增加一个分支都要花费真实的 gas，而分配器刻意不包含 gas 价格项，因为用原生代币计价的 gas 与用交易代币计价的输出相比较，恰恰需要协议拒绝拥有的价格预言机。不依赖预言机的替代方案是一个阈值：只有当 $\mathrm{out}_{\mathrm{split}} \ge \mathrm{out}_{\mathrm{single}} \cdot (1 + 25/10^{6})$——`MIN_SPLIT_IMPROVEMENT_PPM = 25`——时才保留拆分，否则分配收缩为一个分支。这个阈值是一个实测数字：一个分支的 gas 与其改进之间的真实盈亏平衡点在 Base 上测得为 3 ppm（每个额外分支 320 字节 calldata，每字节 105.5 gas），闸门设在约其八倍处，并以百万分之一计，因为四分之一个基点在基点单位中不存在；它的历史——20 bps，然后 5，然后 0.25——记录的是两个从未针对测量校准过的值。当闸门收缩一条路由时，它以全额测量两个单分支候选而不是一个——最深的池子和边际费率最好的池子——因为边际费率会美化浅池，而深度才是承载整笔规模的代理指标；成交更好者胜出。
- **以测量而非余量作保险。** 早先的设计在规划时把较长路由的每个分支削减 5 bps，作为对分支间漂移的保险。随后在同一区块内对 Base 上九个交易对测量了这种漂移：最坏情况 −2 bps，比保险低一个数量级，而每条诚实的多分支路由在每笔交易上都在支付这份保险——是其实测风险的 27×。削减被取消；在实现输出上强制执行的底线以零规划成本承担这一风险。该测量是在平静时段进行的，反方论点也记录在源码中：如果将来要恢复保守性，正确的位置是被检查的底线，而不是只用于排名的估计。

组装好的路由携带 Router 将会重新推导的内容：每个分支的承诺输入与预期输出、路由按份额加权的冲击，以及 Solver 用 Router 强制执行的同一算术所证明的底线 Φ（§11）。Solver 还按类型依据 `THETA_GAS` 阶梯为每个分支的执行定价，并把总和公布为 `estGas`——路由携带的一个参考数字，链上没有任何东西读取它。读者的经验法则在所有这些机制之后依然不变：在确认之前，把路由器声称的改进与你钱包显示的 gas 进行比较。

## §11 执行层与 Iron-Law 底线 Φ

Solver 提议，Router 决断——要么原子地完成，要么完全不做。Router 是唯一移动资金的合约，在交易之间不持有任何资金，并建立在一条原则之上：每个关注点一种机制，普遍适用。凡是能测量的，它一概不作假设。

### §11.1 四个入口，一个执行器

| 入口 | 签名（节选） | 授权方式 | 路由 |
|---|---|---|---|
| `swapExactIn` | `(route, amountIn, userMinOut, recipient, deadline)` | 经典的 `approve` + `transferFrom` | 来自 calldata |
| `swapExactInWithPermit2` | `(route, amountIn, userMinOut, recipient, deadline, permit, signature)` | 通过规范的 Permit2 合约进行一步式 Permit2 签名转账；不向 Router 留下常驻授权额度 | 来自 calldata |
| `swapExactInNative` | `(route, userMinOut, recipient, deadline)` payable | 原生币值，在入口处包装一次；在 `weth` 接好之前失败即关闭（`RouterE(3)`） | 来自 calldata |
| `swapBestExactIn` | `(tokenIn, tokenOut, amountIn, userMinOut, recipient, deadline)` | 经典方式 | 由 Solver 在帧内求解（`findBestRoutePlan`），然后通过一次显式传递付款方的自调用执行 |

只有 `swapBestExactIn` 在交易中调用 Solver；其余三个入口接受调用方在链下通过 Quoter（§12）免费算出的路由。四个入口都汇聚到同一个私有执行器（`_execute`），因此下文的每一项检查都在每个入口上运行。EIP-7702 委托账户调用的入口与合约调用的完全相同；不为它另设入口。

在任何资金移动之前，先执行两项拒绝。零最低值在每个入口都被拒绝——`RouterE(10)`，没有例外，没有兼容开关——因为最低值是合约无法代用户计算的唯一界限，而一道可能缺席的守卫不是守卫。超过三跳、某一跳超过五个分支，或某一跳的输入代币不是上一跳输出代币的路由，以 `RouterE(3)` 拒绝：跳的连续性使每个中间代币在兑换前的“外来”余额成为已知量，因此精心构造的路由无法把一个滞留代币指定为输入，并把 Router 持有的该代币全部余额按比例卷入兑换。

### §11.2 测量，从第一条指令开始

无论使用哪个入口，Router 做的第一件事是测量到账的数量：它在拉取之后读取自身的余额变化，而不是信任名义金额，因此转账时少交付的代币会以其真实规模进入路由。基线只生成一次：输入代币的兑换前余额（`baseIn`）和输出代币的兑换前余额（`toutStart`）在入口处取得，之后的每一次测量都是相对它们的差值，因此已经躺在合约里的代币——粉尘、捐赠、无关历史留下的滞留资金——被排除在兑换可支付的范围之外。设法花到自身基线以下的路由会在检查算术上失败——这是安全的结果，因为那些资金从来就不归这次兑换花费。

多跳路由是一个计划，而计划在每个跳边界都会遭遇现实。Router 根据*实际*到账的余额重新缩放每一跳的分支——第 0 跳按测得的拉取后输入缩放，并以路由承诺的数量为上限（因此 Router 绝不会把预先切好的订单强行塞进一个浅池）；之后的每一跳按测得的、高于其外来基线的桥接余额缩放——每个分支执行 $\mathrm{amt} = \mathrm{amountIn}_{\mathrm{leg}} \cdot \mathrm{real}/\mathrm{planned}$（`_hopScaleImpactAndQuote`）。缩放为零的分支被跳过；未花费的输入和桥接残余被退回给付款方，绝不留给 Router。同一遍处理对每个分支的池状态只读取一次，并从这一次读取中产出该分支的缩放数量、实测冲击及其帧内报价——正是底线所消耗的三个量——因此储备型与集中型家族的测量无需额外的 `staticcall`。

### §11.3 每个分支下的三道底线

**单分支底线。** 每个分支对 Router 输出余额的实测贡献必须达到其界限的 `LEG_FLOOR_BPS = 8,000`——即 80 %——否则整笔兑换以 `RouterE(5)` 回滚（`_execScaled`），因此单个被夹击或被操纵的池会立即使交易失败，而不是把损失藏在一个看似健康的总额里。该界限是调用方证明的报价，按实际花费的数量按比例折算——每当证明覆盖的部分少于帧内实测报价的 `MIN_QUOTE_COVERAGE_BPS = 5,000` 时，*抬高*到帧内实测报价。这里取最大值而非最小值是有意为之：对底线而言，在声明被压低时 `min(claimed, measured)` 返回被压低的那个值并放松约束，而这正是该闸门要封堵的攻击。只要存在任何底线依据——调用方的证明或帧内报价——该守卫就会运行，因此在路由里写入零已不再能关掉调用方自己的底线。其局限：既无可测报价又无证明的交易场所会落到聚合底线和用户最低值上，而它们无论如何都会约束它。

**每跳聚合底线。** 单分支底线是局部的，而组合是全局的：持有 $L$ 个分支之一的攻击者可以从一跳中抽取约 $20\,\% \cdot (L-1)/L$，却不触发任何单一底线。因此每一跳最多只能损失一个*平均*证明分支可以合法损失的数量：$\sum \mathrm{got} + \lfloor (\mathrm{BPS} - \mathrm{LEG\_FLOOR\_BPS}) \cdot \lfloor \sum \mathrm{attested} / n \rfloor / \mathrm{BPS} \rfloor \ \ge\ \sum \mathrm{attested}$——余量是平均证明分支的 20 %，否则 `RouterE(5)`。取均值而不是最大值，是因为在最大值规则下攻击者会抬高自己的分支来抬高共享预算。对单个分支，该规则恰好退化为单分支底线——按构造，不引入任何新的刚性。

**路由底线 Φ** 见 §11.5。

### §11.4 一个回调，一次解锁

每个 V3 型交易场所——Uniswap V3、Algebra、集中型 Solidly 分叉、Pancake V3、Sushi V3——都以不同的回调名称使用同一种闪电记账模式：池在兑换中途回调，带上 token0 的变化量、token1 的变化量和任意数据，要求付款。Router 不为每个分叉提供一个具名回调，而是暴露一个响应所有回调的 `fallback`——即**单一回调原则**：它读取两个变化量，根据其符号判断自己欠的是哪种代币，并精确支付该数量，同时从瞬态存储（`TSLOT_POOL`、`TSLOT_TOKEN`、`TSLOT_AMT`）中取出进行中的分支上下文。由于任何人都能触达 fallback，它在三个方面设防：只向当前分支承诺的池付款；没有进行中的分支时拒绝行动（瞬态上下文在两次兑换之间为零）；释放的数量绝不超过该分支记录的预算——同一分支内的第二次付款要求以 `RouterE(6)` 拒绝。一个采用新回调名称的新上线 V3 分叉，在部署当天即获支持。

V4 单例合约（singleton）被包装在同一个跳接口之后：`unlock`，然后兑换，`sync → settle → take`，重新上锁，币种存放在瞬态存储中，并使用 §5.3 的原生接缝。任何 V4 分支执行之前，Router 读取钩子（hook）地址，若其标志位声明了改变变化量的权限，则拒绝该分支（`RouterE(9)`）；经过筛查的钩子就是被执行的钩子，因为规范的 PoolManager 会原样回传解锁数据（`test/V4SievedHookIsTheExecutedHook.t.sol`）。路由形状规则是全路由范围的规范顺序：一旦某个带钩子的分支已执行，在本跳或之后任何一跳中都不会再执行无钩子分支（`sawHooked`），因此钩子无法在同一路由中后续无钩子分支结算之前观察到它；带钩子的分支只有在其后的每个分支也都带钩子时，才可以位于较早的跳中。

**转账收费（fee-on-transfer），只在能承受它的分支上。** 有些代币每次转账都会少交付。在恒定乘积分支上，Router 以规范模式处理：先转账，再在同一转账后状态下读取池的储备与余额，并按池实际看到的差值为输出定价——这个量按构造正确，因为它恰好就是池自身的不变量将要检查的量。该分支仅在代币被测出短少时启用（`TSLOT_FOT`），启用的代价也一并说明：基于报价推导的路由底线是在不知税费的情况下算出的，因此本次兑换丢弃它；协议底线按实测净比率重新缩放（向上取整，即保守方向）；单分支界限按同一比率重新定价；用户的最低值成为起约束作用的条件。集中型分支在设计上不支持转账收费——闪电记账必须精确支付所欠数量——因此仅含 V3 的路由上的收税代币会在一开始就以 `RouterE(13)` 拒绝，而不是在池内回滚。

### §11.5 Iron-Law 底线 Φ 全貌

并非每条能执行的路由都应该执行——一条只返回公允价值 60 % 的路由比不交易更糟——因此在上述一切之下，还有一道由协议自行推导的底线。它是以基点表示的保留比例（Core `ironFloorBpsShv`、`legShaveBps`）：

$$
\mathtt{floorBps} \;=\; \max\!\left(\;9{,}600 - \mathtt{legShv} - \min(\delta,\, 10^{4}) - \sigma_{\ln}/10^{14},\;\; 8{,}000\;\right)
$$
^e15

$$
\mathtt{legShv} \;=\; \sum_{\mathrm{hops}} \left\lfloor 200 \cdot \frac{(\sum_{i} a_{i})^{2} - \sum_{i} a_{i}^{2}}{\sum_{i} a_{i}^{2}} \right\rfloor \;=\; \sum_{\mathrm{hops}} \left\lfloor 200\,(n_{\mathrm{eff}} - 1) \right\rfloor
$$
^e23

三个常量决定它：`FLOOR_BASE_BPS = 9,600`、`FLOOR_PER_LEG_BPS = 200`、`FLOOR_HARD_MAX_LOSS_BPS = 2,000`。对干净的单分支兑换，底线从 96 % 起步；实测冲击 $\delta$ 每增加一个基点，它放松一个基点；每多一个*有效*分支，放松 200 bps；并被钳制为永不低于 8,000 bps：无论输入如何，协议都绝不会明知故犯地接纳一条保留不足其参考值 80 % 的路由。分支削减量根据交易在各分支间的*集中度*计算——$(\sum a)^{2}/\sum a^{2}$，即有效分支数，$N$ 个等份时恰为 $N$，一个分支占主导时恰为 1——因此拆分所获的放松与其拆分的真实程度成正比，而份额趋于零的分支，无论声明为零还是一 wei，所获放松也趋于零。由 Cauchy–Schwarz 不等式，分子永不下溢。冲击项是路由上各分支实测冲击的份额加权平均。有两条性质作为定义的一部分写明：波动率项 $\sigma_{\ln}$ 存在于签名中，但在每个调用点都以字面量零传入——是为未来估计器预留的接口，目前不起作用；储备型家族的冲击不含费用，而集中型家族的冲击含费用，各自采用其家族规范给出的形式。

使 Φ 成为强制约束而非启发式规则的，是它在哪里运行、作用于什么。交给 Router 的路由携带若干建议性字段——报价总额、证明的底线——而 Router 一个都不信任：它在执行帧内测量每个分支的真实冲击，根据交给它的数量计算分支削减量，重新计算 `floorBps`，并将其应用于**最后一跳在实际到达该跳的数量下的帧内报价**——这是一个以输出代币计价、从本次执行期间读取的池状态推导而来、无法通过 calldata 伪造的参考值。参考值的选择正是守卫得以生效的关键：*已实现*输出的一个比例永远不可能超过已实现输出本身。当最后一跳无法在帧内报价时——当前 tick 处的流动性缺口、费用哨兵值——参考值回退到该跳的证明报价，该报价已被覆盖率闸门抬高、并经转账收费测量重新定价，因此浅池上的即时（JIT）流动性缺口无法解除底线；底线的锚点始终是一个转移了价值并产出路由输出的跳。该检查作用于总输出，在任何输出侧费用之前。有效最低值是三者中的最大值，

$$
\mathtt{effMin} \;=\; \max\!\left(\mathtt{userMinOut},\;\; \mathtt{route.singleOutFloor},\;\; \left\lceil \mathtt{finalHopQuote} \cdot \mathtt{floorBps}/10^{4} \right\rceil\right)
$$
^e16

其不对称性正是要点所在：调用方提供的字段可以收紧保护，却永远无法放松它。Solver 在相同数量上用同样的 `legShaveBps` 与 `ironFloorBpsShv` 证明 `singleOutFloor`，因此对 Solver 构建的路由，证明的底线与强制的底线按构造一致（`test/FloorParitySolverRouter.t.sol`）；§15 的制度测试框架在每个生成的行上锁定这两个帧：费用从输入中扣除时，强制底线位于 $[\mathrm{attested} \times (1 - \mathrm{fee}),\ \mathrm{attested}]$ 之内；费用从输出中扣除时，它等于证明的底线。

![FIG-7 — Iron-Law 底线：单分支、两个等额分支和四个等额分支下保留比例随实测冲击的变化；80 % 硬性钳制；并标出算例 3 的位置。](https://blazephoenix.xyz/whitepaper/figs/zh/fig-7.png)

**算例 3——两跳路由上的底线。** 路由 A → WETH → B：第 0 跳将 600 A 送入池 P、400 A 送入池 Q；第 1 跳将产出的 WETH 经单个池 R 送出。帧内测得：第 0 跳的分支冲击分别为 100 和 60 bps，第 1 跳的分支为 40 bps，整条路由上的份额加权平均为 80 bps。第 1 跳在实际到达的 WETH 数量下的帧内报价为 1,000.000 B。

1. 第 0 跳集中度：$(600 + 400)^{2} = 1{,}000{,}000$；$600^{2} + 400^{2} = 520{,}000$；$n_{\mathrm{eff}} = 1.923$；削减量 $= \lfloor 200 \times 480{,}000 / 520{,}000 \rfloor = \lfloor 184.6 \rfloor = 184$ bps。
2. 第 1 跳只有一个分支：$(\sum a)^{2} - \sum a^{2} = 0$；削减量为 0。`legShv` 合计 = 184。
3. $\mathtt{floorBps} = \max(9{,}600 - 184 - 80 - 0,\ 8{,}000) = 9{,}336$：该路由必须保留其参考值的 93.36 %。
4. $\mathtt{protocolFloorOut} = \lceil 1{,}000.000 \times 9{,}336 / 10{,}000 \rceil = 933.600$ B。
5. 交易者设定 `userMinOut` = 990 B，Solver 证明 `singleOutFloor` = 933.6 B，则 `effMin` = 990 B——用户自己的界限起约束作用，在诚实路由上本应如此。交付 998.4 B 则结算；交付 985 B 则以 `RouterE(5)` 拒绝，整笔交易连同其中每个池的兑换都如同从未发生。

假如交易者设定 `userMinOut` = 900 B，协议底线将在 933.6 B 处起约束作用：一笔 930 B 的成交，低于帧内参考值 7 %，即便越过了用户自己的数字，也会被拒绝。

### §11.6 结算，以及如何解读一次结算

结算以开场的方式收尾：靠测量。Router 取输出代币相对入口基线的变化量作为总输出（若为零则 `RouterE(8)`），执行上述底线检查，在制度规定的位置收取费用（§13），将净额转给接收方并测量*接收方*的余额变化，在该交付数量上强制 `userMinOut`——因此转账收费的输出代币无法让用户滑落到其界限之下——并读取一次费用账本：未向协议支付任何费用的结算被拒绝（`RouterE(15)`），在锚定路由上第二次付费也被拒绝（`RouterE(16)`）。然后，且仅在成功路径上，它对每个已执行分支调用一次 Hub 的 `recordSwap`（`_recordHits`），传入该跳实际能够花费的数量——即对每个分支应用实测与声明之比——这是一次兑换执行的唯一外部写入；底线拒绝时不写入任何内容。

每次结算都会发出 `ExecutionProof(user, tokenOut, quoted, realized, floorUsed, blockNumber)`：与执行在同一帧内产出的参考报价，作为链上序列公开，任何人都可以在该区块对 `findBestRoutePlan` 发起 `eth_call` 重新推导。其字段，不作夸大：`user` 是付款方，绝不是 `msg.sender`；`quoted` 是最后一跳的报价——它证明的是最后一跳，而非整条路由；`realized` 是实际交付的数量，在接收方处测量；`floorUsed` 是必须超过的协议底线。每个 `Fee(token, amount, toT1, toT2)` 事件写明代币及其分配。

**算例 6——解读一次结算。** 算例 3 的路由结算，发出 `ExecutionProof(0xUSER, B, 1,000.000, 998.400, 933.600, N)` 和一个 `Fee(WETH, 0.014, 0.0042, 0.0098)`。

| 量 | 值 | 解读 |
|---|---|---|
| `quoted` | 1,000.000 B | 最后一跳在实际到达的 WETH 数量下的帧内报价 |
| `realized` | 998.400 B | 交付给接收方并在该处测量；为报价的 9,984 bps |
| `floorUsed` | 933.600 B | 对报价应用 `floorBps` 9,336；成交高出它 64.8 B |
| `Fee` | 0.014 WETH，一个事件 | 锚定制度：第 0 跳产出的 5.000 WETH 的 28 bps，在第 1 跳的输入处支付，30 % 归第一金库；未从 B 中扣取任何费用 |
| 距 `userMinOut` 的差距 | 8.4 B | 用户 990 B 的界限留有 0.84 % 的余量 |

交付减去报价是市场的答案，而不是协议的：费用早已以 WETH 收取，这条路由上不存在输出侧扣费。以输出代币计价的 `Fee` 事件只出现在直接进入桥接币的路由上（§13）。

### §11.7 Router 的拒绝

| 代码 | 含义 | 位置 |
|---|---|---|
| `RouterE(1)` | 未授权的控制调用 | `onlyControl` |
| `RouterE(2)` | 已暂停，或在暂停期间尝试放弃控制权 | `whenLive`、`renounceControl` |
| `RouterE(3)` | 错误输入——零地址、未接通的原生入口、跳数、每跳分支数、跳不连续 | 各入口、`_execute` |
| `RouterE(4)` | 已过截止时间 | 各入口 |
| `RouterE(5)` | 输出低于某道底线——单分支、每跳聚合、路由底线或 `userMinOut` | `_execScaled`、`_execute` |
| `RouterE(6)` | 回调未获授权——池不对、无进行中的分支、第二次付款要求 | `fallback` |
| `RouterE(7)` | 重入 | `nrEntrant`（瞬态锁） |
| `RouterE(8)` | 兑换失败——零输出、未知类型、费用大于或等于数量 | `_execute`、`_execScaled`、`_chargeHopFee` |
| `RouterE(9)` | V4 钩子改变变化量 | V4 分支预承诺 |
| `RouterE(10)` | `userMinOut == 0` 且 `amountIn > 0` | 每个入口 |
| `RouterE(13)` | 仅含集中型分支的路由上出现转账收费代币 | `_execute` |
| `RouterE(14)` | 救援未排队，或仍在其 48 小时延迟期内 | `executeRescue` |
| `RouterE(15)` | 结算时未支付协议费用 | 费用账本，`_execute` 末尾 |
| `RouterE(16)` | 锚定路由上费用被支付两次 | 费用账本，`_execute` 末尾 |

代码 11 和 12 未分配。一个与 API 同样可枚举的回滚面，使 §15 的制度数组能用同一条规则评判每一行——要么结算，要么以我们自己的选择器拒绝——并把其他任何结果称为第三种结局。

## §12 报价界面，以及报价如何老化

一个叫作“你的报价”的数字可以来自两个地方，而它们是不同的代码路径：**Quoter**，一个界面在你签名之前调用的只读预览合约；以及**帧内路径**，即 Solver 与 Router 在执行交易内部计算报价。§4.4 给出了各类型的真实情况；本节给出各个界面，并测量它们之间的差距。

### §12.1 Quoter 的界面

| 函数 | 返回 | 说明 |
|---|---|---|
| `previewPlan(tIn, tOut, amountIn)` | 一个 `Preview` | Solver 的计划，连同费用与安全缓冲一起打包 |
| `previewPlanWithMinOut(…, userMinOut)` | 一个 `Preview` | 同上，并以调用方的最低值判断 `canExecute` |
| `previewAndEncode(…)` / `previewAndEncodeWithMinOut(…)` | 一个 `Preview` 以及 `swapExactIn` 的 calldata | 集成方获取报价的方式——§12.2 的研究正是使用它 |
| `batchQuote(entries[])` | 最多 `MAX_BATCH = 32` 个预览 | 无法规划的交易对留下一个零初始化条目 |
| `previewPlanExact(tIn, tOut, amountIn)` | 路由及精确的净输出 | 精确通道（Exact Pass）：每个集中型分支都针对池自身的兑换进行试运行 |

**预览是什么。** `Preview` 结构体在设计上是建议性的——起约束作用的检查是 Router 在帧内重新推导的那些——其字段在定义处有文档说明：`grossOut` 回显计划的总额；`protocolFee` 是费用对输出的影响，按制度精确地以 Router 收取的方式建模（§13）——在锚定路由上收一次，在穷尽路由上每跳收一次，并像 Router 那样向上取整；`safetyBuffer` 是分支间缓冲

$$
s \;=\; \min\!\left(\max(0,\, n-2) + 5a,\;\; 10\right)\ \text{bps}
$$
^e21

两个及以下分支时为零，超过两个分支后每个分支一个基点，另外每个按*假定*费用定价的恒定乘积分支（Core 在其上限之下替换了声明费用的情形）再加五个基点，共用一个上限十，因为没有上限的缓冲不再是缓冲，而成了底线；`netOut` 为 $\mathrm{grossOut} - \mathrm{protocolFee} - s$；`ironFloor` 回显证明的底线；`topology` 与 `bridgeUsed` 由跳数以及 Router 将使用的费用锚点推导——对同一产出方的同一次扫描，因此预览与执行器不可能指认不同的桥接币。集成方规则一句话即可说清，也是本文中最举足轻重的建议：根据你自己的价格预期推导最低值，绝不要从预览字段中推导。

**精确通道。** 为了对集中型交易场所做出与池完全一致的预览，Quoter 调用池真实的兑换入口；池回调要求付款；Quoter 的回调并不付款，而是回滚——在回滚载荷中携带计算出的变化量。回滚撤销所有状态，不支付任何东西，解码出的输出就是该交易场所在实时状态上自己的兑换，运行后又被回滚；V4 的处理方式完全相同，通过一次回调以打包变化量回滚的解锁完成。拒绝试运行的池保留计划自身的声明值，按其下方的弦缩放——绝不在其上方，因为 AMM 的输出是凹的。第 0 跳以计划承诺的数量为上限，因此受容量钳制的路由不会在 Router 永远不会花费的规模上试运行。自 2026-09-03 起，返回的标量已扣除协议费用，并像预览那样只扣一次，因此由它推导出的最低值会被底线所遵守（`test/QuoterExactNetOut.t.sol`）。这是 Quoter 在预览侧的工具；起约束作用的界面是帧内重新推导。

### §12.2 报价如何老化

报价是关于未来某个区块的承诺。本研究以集成方的方式获取报价——`previewAndEncode` 返回预览与 calldata——然后让世界变动（由他人经同样的池进行零到三笔交易，每笔最多占浅侧储备的 3 %，且全部与用户同向，因此每一笔都对用户不利），让零到十秒流逝，再原样执行该 calldata。在由恒定乘积模拟池构成的三代币宇宙（A、B = 桥接币、C；直接进入桥接币、经由它的两跳、反方向的两跳）上取 240 个样本，每个结果都被分类（`test/QuoteDelayStatistics.t.sol`）：

| 报价与执行之间的漂移 | 样本 | 已结算 | 被底线拒绝（`RouterE(5)`） | 交付 / 预测——均值 | 最小值 |
|---|---|---|---|---|---|
| 无 | 64 | 64 | 0 | 10,000 bps | 10,000 |
| 1 – 100 bps | 43 | 43 | 0 | 9,952 bps | 9,803 |
| 100 – 300 bps | 133 | 102 | 31 | 9,966 bps | 9,653 |

| 报价与执行之间的延迟 | 样本 | 已结算 | 被拒绝（`RouterE(5)`） | 交付 / 预测——均值 | 最小值 |
|---|---|---|---|---|---|
| 0 s | 17 | 15 | 2 | 9,989 bps | 9,857 |
| 1 – 5 s | 99 | 89 | 10 | 9,959 bps | 9,653 |
| 6 – 10 s | 124 | 105 | 19 | 9,983 bps | 9,659 |

![FIG-8 — 报价如何老化：按漂移分组的已结算与被拒绝样本，以及每个已结算样本的交付/预测比；同样的 240 个样本按延迟分组则不显示任何趋势。](https://blazephoenix.xyz/whitepaper/figs/zh/fig-8.png)

时间不会改变报价；漂移才会。在每个样本上断言：无漂移的报价在任何延迟下都能结算，并精确交付其预测值（64 个中的 64 个）；结算交付的数量永远不低于预览证明的底线；不存在第三种结果。截止时间之后（`deadline = now + 5`，在 `+10` 执行），20 个中的 20 个都以截止时间自己的代码 `RouterE(4)` 被拒绝，没有一个结算。在最多 1 % 的不利漂移下，每个报价仍能成交，且与预测相差在 2 % 以内；在 1–3 % 的漂移下，底线拒绝其中四分之一，而不是以低于证明输出的结果成交，成交结果与预测相差在 3.5 % 以内——这正是从报价一侧看到的 §14 夹击曲线。

**Base 实链**（`test/fork/QuoteDelayFork.t.sol`，1,000 USDC → WETH，真实的池，协议部署在当前区块的分叉上）：在没有其他变动的情况下，分别于 0、3、6 和 10 s 后执行，报价四次都精确交付了其预测值。在同一路由上先行交易 10,000 · 50,000 · 200,000 · 1,000,000 · 5,000,000 USDC，并在 10 s 后执行过时的 calldata，五笔全部在底线之内结算，分别为预测值的 9,999 · 9,998 · 9,994 · 9,974 · 10,000 bps：在一千美元交易之前抢先成交一百万美元，使这笔一千美元的交易损失四分之一个百分点，而那笔五百万的交易所经过的池，一千美元的路由根本不触及。上面的分布基于模拟池；Base 实链在一个区块的一个交易对上给出实测范围，而非分布。

### §12.3 通过 ABI 获取报价的成本

围绕外部调用测量的 gas：在三代币宇宙上各取四十个规模（`test/QuoterGasStatistics.t.sol`），在 Base 实链上取五个规模（`test/fork/QuoterGasFork.t.sol`）：

| 环境 | `previewPlan` 均值 | 最小值 | 最大值 | σ | `previewAndEncode` 均值 | σ |
|---|---|---|---|---|---|---|
| 模拟池——发现：交易对仅为工厂所知，找到一个池 | 121,313 | 116,468 | 123,491 | 1,433 | 123,317 | 1,851 |
| 模拟池——新鲜注册表：为三个预置池定价 | 235,574 | 227,205 | 237,843 | 1,815 | 239,647 | 1,937 |
| Base 实链——冷：注册表为空，扫描已准入的工厂 | 1,524,221 | | | | 1,525,341 | |
| Base 实链——热：一次执行后保持新鲜，已注册两个池 | 1,414,633 | | | | 1,416,037 | |
| Base 实链——超过发现 TTL 后再次变冷 | 1,359,925 | | | | 1,361,582 | |

在模拟池上对十个条目执行 `batchQuote`：2,055,390 gas，每个条目 205,539。新鲜注册表的模拟池比发现更贵，因为它为三个池定价，而发现只找到一个；诚实的比较是实链上的那一组，其中发现扫描约占一次报价的 7 %——而报价是一个 view 调用，集成方永远不必在链上为它付费。

## §13 费用政策：两种制度与盈余规则

*通俗地说：*协议只收一次 0.28 %，从一个实测金额中收取，收取的是金库愿意持有的币，并且会清点它确实收了。*精确地说：*`PROTOCOL_FEE_BPS = 28` 是 Core 中的编译期常量，已部署字节码中任何地方都没有它的设置函数；费用为 `mulDivUp(base, 28, 10,000)`——向上取整，因此对任何非零基数都不可能出现零费用——按 `TREASURY1_SHARE = 3,000` bps 分给第一金库，余下部分归第二金库（以 `fee − t1` 计算，因此两者之和总是恰好等于费用，没有零头），两个金库在构造时确定，并可由单向门永久冻结。没有任何密钥能对交易者提高费率，也没有任何密钥能为受偏爱的集成方降低费率：费用问题在编译期就已回答，并从密钥能做的事情清单中删除。

### §13.1 费用在哪里收取：两种制度，都有名字

自 2026-08-22 起，规则只有一句话：**只收一次，收在 Router 持有的第一个桥接币上。** Router 扫描路由，寻找第一个输入代币是已注册桥接币的跳（`hub.isBridgeToken`，按跳的顺序）——该跳即 `feeHop`——并对该跳的*实测*输入收取 28 bps：在第 0 跳上，是以路由承诺量为上限的实测拉取量；在后续跳上，是 Router 持有的该桥接币中高于其外来基线的余额，这个量本身已能抵御转账收费（fee-on-transfer）与杂散余额。此后 Router 在该路由上不再收取任何费用。目的地本身就是桥接币的直接路由（TOKEN → WETH）则改为在输出上收费，且在底线检查之后——底线验证兑换质量，协议的抽成从已通过验证的金额中扣除，用户的最低值则与其实际收到的金额比较。这就是**锚定制度**。为什么收在桥接币上而不是目的地上：桥接币是 WETH 和 USDC，金库收到的是它愿意持有的流动币种，而不是作为目的地的某个长尾代币的零头。为什么收在第 1 跳的输入上而不是第 0 跳的输出上：两者是同一个代币、同一个金额，但第 1 跳的输入由真实余额测量，而这正是 Router 本来就在做的测量。

这条规则还有第二种制度，直到 2026-09-05 那句话才给它命名。一条手工构建、经过注册表不会收录的池子、且任何一跳的输入都不是桥接币的路由，永远找不到 `feeHop`；此时决定收费的谓词对*每一*跳都为真，每一跳都对自己的实测输入支付 28 bps。这就是**穷尽制度**，它是一条刻意的规则，而不是疏漏：当天曾在测试套件中尝试对这类路由只在第 0 跳收一次费，结果重新打开了穷尽政策本来要关闭的逃逸口——一个没有价值的第一跳把收费点带到零头上，而真正的那一跳什么都不付（`test/FeeEscapeViaJunkPrefix.t.sol`）；五个固定测试在同一次运行中拒绝了这一改动。不存在任何一个位置，能插入零头而逃过每一跳——这就是“穷尽免疫”的含义。Solver 构建的每条多跳路由都经过已注册的桥接币，因此 Solver 构建的路由总是恰好支付一次；穷尽制度是调用者绕开注册表自行路由时遇到的情况，Quoter 也对它建模（没有任何跳的输入是桥接币时，`_pack` 收取 `hops.length` 次，否则收取一次），因此在两种制度下预览与交付都一致（`test/ExhaustionRegimePreviewParity.t.sol`）。

![FIG-9 — Router 判定的两种费用制度：扫描各跳，寻找第一个桥接币输入；锚定路由在该跳支付一次（或在直接进入桥接币的路由的输出上支付）；没有桥接输入的路由每跳支付一次；账本会计数，拒绝零次，并在锚定路由上拒绝两次。](https://blazephoenix.xyz/whitepaper/figs/zh/fig-9.png)

### §13.2 承诺只有一个生产者，且合约会计数

两种制度还配有两道封印。一跳所声明的各分支输入之和——即第 0 跳的费用基数和缩放的分母——由一个函数 `_legSum` 计算；2026-09-05 之前，二者各自在自己的循环里对分支求和，同一个数字有两个生产者。另一道是费用账本：`_payFee` 是唯一转移费用的函数，它在一个瞬态槽（`TSLOT_FEE`）中计数；每次结算读取该槽一次，拒绝没有支付任何费用的交付（`RouterE(15)`），在锚定路由上拒绝第二次支付（`RouterE(16)`），然后将其清零。账本的两项检查是*保险带*：单独来看，没有任何测试能让它们触发，因为它们前面的谓词不留下任何不付费就结算、或在锚定路由上支付两次的路径。它们是合约在运行时拒绝测试在审查时所拒绝的东西，针对的是尚不存在的路径；它们被列为保险带，在任何地方都不计为已覆盖，也不在变异防护之列——变异防护只接纳被某个有名字的测试杀死的变异体。

### §13.3 盈余规则

**盈余规则**是费用设计的对齐论证，按代码的实现方式陈述如下：协议的抽成是一个实测基数的 28 bps，在锚定路由上收一次，在穷尽路由上每跳收一次；结算中任何地方都没有随报价与交付之差而变化的项。当基数是输入时——每条多跳路由，以及每条目的地不是桥接币的直接路由——输出不受影响：池子交付的高于报价的全部部分都完整到达接收方，费用不会因为成交结果有利而上升。当基数是输出时——直接进入桥接币的路由——费用是总交付额（含盈余）的 28 bps，仅此而已。聚合器最容易动手抽成的维度，正是报价与成交之间的差距；本设计对这一差距不设任何费用项，因此标称费率就是真实且唯一的费率。基数从不从 calldata 读取：`route.totalOut` 作为陌生人的声明到达 Router，没有任何代码读取它（`test_FeeBase_IgnoresLiedAboutTotalOut`）。

**算例 5——一条路由上的两种制度。** 桥接币为 {WETH, USDC}；交易者卖出 10,000 A。

*锚定，两跳。*A → WETH → B。第 0 跳不收费（其输入 A 不是桥接币）。第 0 跳的池子付出 5.000 WETH，以 Router 的 WETH 余额高于其外来基线的部分来测量。`feeHop` = 1：费用为 $\lceil 5.000 \times 28 / 10{,}000 \rceil = 0.014$ WETH，0.0042 分给第一金库，0.0098 分给第二金库，第 1 跳将 4.986 WETH 投入 B。一个 `Fee` 事件；账本读数为 1，检查通过；预览恰好扣除了一次 28 bps。

*锚定，直接进入桥接币。*A → WETH，一跳完成。输入上不收费。池子交付总额 5.000 WETH；底线按 5.000 检查；随后支付输出侧费用 $\lceil 5.000 \times 0.0028 \rceil = 0.014$ WETH，交付 4.986 WETH；`userMinOut` 与 4.986 比较。一个 `Fee` 事件，以输出代币计价。

*穷尽，两跳。*A → C → B，其中 A、C、B 都不是桥接币——这是 Solver 不会构建的路由。第 0 跳支付 $\lceil 10{,}000 \times 0.0028 \rceil = 28$ A，并将 9,972 A 投入其池子，池子付出 2,000 C；第 1 跳支付 $\lceil 2{,}000 \times 0.0028 \rceil = 5.6$ C，并将 1,994.4 C 投入 B。两个 `Fee` 事件；账本读数为 2，且没有 `feeHop`，因此 `RouterE(16)` 不适用；有效费率为 $1 - 0.9972^{2} = 55.9$ bps，预览也是这么说的。

### §13.4 从 Router 外部测量的费用

`test/FeeSeals.t.sol` 不读取 Router 的任何数字：费用代币来自规则与桥接币列表，基数来自池子的余额差（从 Router 流入收费跳的金额，或上一跳的池子付出的金额）或接收方的余额差，费用来自金库的余额差，次数来自 `Fee` 事件——覆盖 Router 接受的所有形态（一到三跳；桥接币不出现，或位于第一、中间、最后位置；每跳一个或两个分支），模糊测试金额从 $10^{12}$ 到 $10^{21}$ wei，2,000 次运行，无一失败，每次结算后 Router 都不持有任何资产。

| 路由形态 | 制度 | 费用落在何处 | 实测 |
|---|---|---|---|
| A → B（均非桥接币） | 穷尽，一跳 | 第 0 跳的输入，一次 | fee = ⌈28 bps × 输入⌉，一个事件 |
| W → A（桥接币输入） | 锚定 | 第 0 跳的输入 | 同上 |
| A → W（桥接币输出，直接） | 锚定，输出侧 | 输出 | fee = ⌈28 bps × 总输出⌉，交付 = 总输出 − fee |
| A → C → B（无桥接币） | 穷尽，两跳 | 每跳的实测输入 | 两个事件 |
| W → A → B | 在第 0 跳锚定 | 第 0 跳的输入 | 一个事件 |
| A → W → B | 在第 1 跳锚定 | 第 0 跳产出的桥接币 | 一个事件，⌈28 bps × 第 0 跳池子付出的金额⌉ |
| A → C → W（桥接币仅作为两跳的输出） | 穷尽 | 每跳的输入 | 两个事件 |
| A → C → D → B · A → W → C → B · A → C → W → B | 同上 | 同上 | 3 · 1 · 1 个事件 |

**费用测试发现缺陷的频率**是实测的，而不是假设的（`docs/assurance/fee-seal-detection.json`）：每一个费用变异体——制度谓词向任一方向移动、承诺生产者、账本的两项检查，以及不变量研究中的三个费用变异体——在每个模糊测试下用二十个模糊种子运行，在每个确定性测试下运行一次；检出率以 Wilson 95 % 区间报告，在没有漏检的情况下，再给出漏检概率的三法则上界。

| 变异体 | FeeSeals 模糊测试 | Router 测试活动（2 跳，2 分支） | 覆盖数组 t = 2 | 垃圾前缀逃逸 | 穷尽制度预览一致性 |
|---|---|---|---|---|---|
| 穷尽制度只对第 0 跳收费 | 20/20 [0.84, 1.00] | 20/20 [0.84, 1.00] | 否 | 是 | 是 |
| 穷尽制度跳过第 0 跳 | 20/20 [0.84, 1.00] | 20/20 [0.84, 1.00] | 否 | 是 | 是 |
| 承诺只计第一个分支 | 20/20 [0.84, 1.00] | 20/20 [0.84, 1.00] | 否 | 否 | 否 |
| 费用翻倍 | 20/20 [0.84, 1.00] | 20/20 [0.84, 1.00] | 是 | 是 | 是 |
| 输入侧费用从不收取 | 20/20 [0.84, 1.00] | 20/20 [0.84, 1.00] | 否 | 是 | 是 |
| 两侧都收费 | 20/20 [0.84, 1.00] | 20/20 [0.84, 1.00] | 否 | 是 | 是 |
| 保险带：不再拒绝无费用的结算 | 0/20 [0.00, 0.16] | 0/20 [0.00, 0.16] | 否 | 否 | 否 |
| 保险带：不再拒绝锚定路由上的重复支付 | 0/20 [0.00, 0.16] | 0/20 [0.00, 0.16] | 否 | 否 | 否 |

![FIG-10 — 各测试对各费用变异体的检出率热力图：杀死次数与运行次数之比，附 Wilson 区间；两道保险带显示为没有任何测试能看到的行。](https://blazephoenix.xyz/whitepaper/figs/zh/fig-10.png)

横向读一行：哪些测试能看到这个缺陷。纵向读一列：一个测试能看到什么、看不到什么。第一次测量发现，Router 测试活动看不到放过第 0 跳的穷尽制度变异体，也看不到承诺生产者，因为它只构建直接的单分支路由；当天测试活动即被扩展为走两跳、把第 0 跳拆到两个池子上，并在测试空间中加入一个桥接币，使一次测试活动覆盖所有制度，如今两者都是 20 次中检出 20 次。覆盖数组只能看到费用翻倍，因为它的各行总会经过桥接币。二十个种子 20 次中检出 20 次，将单次测试活动的漏检概率限制在 15 % 以内，这就是变异防护同时运行有名字的测试和测试活动的原因。

按本文惯用的形式——主张、强制位置、局限——总结本节：没有人能改动费率或分配比例，因为二者在已部署字节码中都没有设置函数；调用者无法通过少报报价来缩小费用，因为基数是实测余额，且 `route.totalOut` 不被任何代码读取；调用者无法用没有价值的前缀逃避费用，因为没有桥接输入的路由每一跳都要付费；一次结算不可能什么都不付，也不可能在锚定路由上支付两次，因为 Router 会计数——局限在于，计数器自身的两项检查是保险带，没有任何测试能让它们触发。

## §14 安全模型

*通俗地说：*Router 在交易之间不持有任何资产，每次兑换都是全有或全无，本仓库考虑过的每一类攻击，要么由一个有名字的检查应对，要么被明确列为不在范围内。*精确地说：*威胁目录是 `docs/assurance/threats.json`，包含取自公开漏洞利用记录的 23 类攻击；每一类都写明拒绝它的守卫符号，一旦该符号离开 `src/` 或所列测试离开 `test/`，CI 脚本就会让构建失败。目录的覆盖面是“已考虑范围”的下限，绝不是“实际存在范围”的上限。

### §14.1 攻击与拒绝它们的检查

| 类别（id） | 拒绝它的检查 | 强制位置 | 状态 | 证明该检查可以失败的测试 |
|---|---|---|---|---|
| 重入（DASP-1） | 每个移动价值的入口都有瞬态锁 `nrEntrant`；回调接口会认证其调用者 | Router `nrEntrant` → `RouterE(7)`；`fallback` → `RouterE(6)` | 已阻止 | `invariant_reentrancyBlocked`（`test/RouterAdversarialV4FromV1.t.sol`） |
| 访问控制（DASP-2） | 四个角色；每个特权入口都有门控；控制层可永久放弃 | Hub `onlyAdmin` / `onlyControl` → `HubE(1)`；Router `onlyControl` → `RouterE(1)` | 已阻止 | `test/HubAllowHookAfterRenounce.t.sol`、`test/ControlEvents.t.sol` |
| 算术上溢/下溢（DASP-3） | 全程使用受检算术；每个 `unchecked` 块都附有书面界限；困难曲线的可表示性在边界处测试（`MAX_SQRT_PRICE_MINUS_ONE`） | Core | 已阻止 | `test/BoundaryEquality.t.sol`、`test/CompilerPanicSurface.t.sol` |
| 无界迭代导致的拒绝服务（DASP-5） | 路由的每个维度都有界：`MAX_HOPS = 3`、`MAX_LEGS_PER_HOP = 5`、`MAX_LEGS = 11`、`MAX_CANDIDATES = 8`、`MAX_SLOTS = 16`、`MAX_FACTORIES = 16` | Router `_execute` → `RouterE(3)`；Solver；Hub → `HubE(4)`（工厂）、`_canInsert`（槽位） | 已阻止 | `test/RouteHopCeiling.t.sol` |
| 交易顺序依赖 / 三明治攻击（DASP-7） | Iron-Law 底线，硬性钳制在 `FLOOR_HARD_MAX_LOSS_BPS = 2,000`，独立于调用者的最低值强制执行，调用者的最低值只能收紧它 | Core `ironFloorBpsShv`；Router `_execute` → `RouterE(5)` | 已阻止（有界，§14.3） | `test/regime/SandwichCurve.t.sol`；`invariant_DeliveredNeverBelowTheProtocolFloor` |
| 经由交易场所的跨函数重入（SWC-107） | 同一个瞬态锁覆盖整个兑换，包括池子回调 | Router `nrEntrant` | 已阻止 | `test/V4LockedRegionReentrancy.t.sol` |
| 价格预言机操纵（SOK-ORACLE） | 不存在喂价：参考报价在执行帧内由所交易的场所产生，底线由它推导（`ironFloorBps`） | Core；Router `_execute` | 已阻止 | `test_Parity_SplitRoute_AttestedFloorEqualsEnforcedFloor`（`test/FloorParitySolverRouter.t.sol`） |
| 以调用者提供的数量替代实测数量（SOK-FEE-BASE） | 费用基数是实测余额（`_chargeHopFee`）；`route.totalOut` 不被任何代码读取 | Router `_chargeHopFee` | 已阻止 | `test_FeeBase_IgnoresLiedAboutTotalOut`（`test/BlazePhoenixRouter.t.sol`） |
| 转账收费与 rebasing 代币（SOK-FOT） | 每个关键金额都是实测的余额差（`balanceOf`），从不是假定的转账金额 | Router，每道接缝 | 已阻止 | `test/FotFloorReprice.t.sol`、`test/PartialFotAtPrePulledDoors.t.sol` |
| 恶意场所被纳入注册表（SOK-VENUE-ADMISSION） | 只有策展人可以纳入，每个地址一行；推导来源在纳入时被证明（`factoryDeployer`），放弃控制后冻结 | Hub `addFactory`、`_probe` | 已阻止 | `test_C4_FirstPin_AfterRenounce_MustNotAttestTheLiveAnswer`（`test/T19ReadmissionEdge.t.sol`） |
| 已纳入场所的逻辑在代理后面变动（SOK-PROXY-VENUE） | 放弃控制后，若运行时代码已变动则拒绝重新纳入（`factoryCodehash`）；对于代理可以不改代码就改变回答的情况，改为固定该回答 | Hub `addFactory` → `HubE(1)` | 已阻止 | `test/FactoryCodehashPin.t.sol`、`test/RenouncedFactoryRearm.t.sol` |
| 固化后场所行从推导式转为询问式（SOK-MODE-FLIP） | 一旦 `controlRenounced`，推导行不能变成询问行；反方向的收紧仍然允许 | Hub `addFactory` | 已阻止 | `test_C4_S3_DeriveRowMustNotBecomeAnAskRowAfterRenounce`（`test/T19ReadmissionEdge.t.sol`） |
| 公开指标报告的是调用者的声明（SOK-VOLUME） | 交给注册表的是该跳实际能花费的金额，由实测与声明之比（`hopScale`）得出 | Router `_recordHits` | 已阻止 | `test_INV_F4_VolumeInEqualsTheMeasuredPoolDelta`（`test/VolumeEventFidelity.t.sol`） |
| 预览无法预测执行（SOK-QUOTE-EXEC） | 在两种费用制度下都断言预览与交付相等（`previewRoute`、`_pack`） | Quoter；Router | 已阻止 | `test_INV_F2_PreviewPredictsDeliveryWithNoBridge`（`test/ExhaustionRegimePreviewParity.t.sol`） |
| 确定性推导被引向攻击者的地址（SOK-V4-DERIVE） | CREATE2 原像只有一个生产者（`create2Address`）；池 ID 由其自身的 key 推导；`hasCode` 与存活性证明丢弃无法解析的结果 | Core；Hub `_probe`、`_scanV4` | 已阻止 | `test/ConditionAdequacyCore.t.sol`、`test/KindIsDerivedNotDeclared.t.sol` |
| 带钩子场所上的恶意钩子（SOK-HOOK） | 三层防护，§14.2：不可变的地址位、带 codehash 固定的允许列表（`hookAllowed`、`isHookLive`）、投影算子 Ξ | Router → `RouterE(9)`；Hub `allowHook` → `HubE(8)`；Solver `_topKPools` | 已阻止 | `test/V4SievedHookIsTheExecutedHook.t.sol`、`test/SeedPoolHookMustBeAllowed.t.sol`、`test/RenouncedHookRearm.t.sol` |
| 通过重复纳入耗尽注册表（SOK-GRIEF-SEATS） | 每个地址一行；重复添加会原地刷新，而不是占用一个席位（`MAX_FACTORIES`） | Hub `addFactory` → `HubE(4)` | 已阻止 | `test/RenouncedFactoryRearm.t.sol` |
| 任意外部调用或 transfer-from 汇点（SOK-ARBITRARY-CALL） | 执行器从不接受调用者提供的调用目标；与场所的交互从一组按类型选择的封闭形态中分派（`_execScaled`），未知类型会回滚 | Router `_execScaled` → `RouterE(8)` | 已阻止 | `test/regime/HostileVenueMatrix.t.sol` |
| 委托授权的签名重放（SOK-SIG-REPLAY） | 委托授权由标准的 Permit2（`permitTransferFrom`）处理；系统本身不持有任何签名方案 | Router `swapExactInWithPermit2` | 已阻止 | `test/RouterPermit2OneStep.t.sol` |
| 治理劫持（SOK-GOV） | 不存在治理：没有代币投票，没有时间锁，没有代理；仅有的特权是场所纳入与暂停，二者都可放弃 | — | 不在范围内 | — |
| 恶意升级（SOK-UPGRADE） | 合约不可变；没有代理，也没有实现槽 | — | 不在范围内 | — |
| 外部桥或交易场所被攻破（SOK-BRIDGE-EXT） | 第三方场所是被组合的，而不是被控制的；它们的失败在此由底线和调用者的最低值限定，不对其内部安全性作任何声明 | — | 不在范围内 | — |
| 用户私钥被盗（SOK-KEY） | 位于信任边界之外；之所以记录，是因为公开的事件数据将很大一部分损失归因于此 | — | 不在范围内 | — |

二十三类中有十九类由有名字的守卫应对；四类不在范围内，并记录了原因。目录还从另一个方向由资产闭包（`assets.json`）交叉检验：系统持有或决定的六样东西——在途资金、委托额度、协议费用、注册表完整性、滞留余额、调用者 gas——与东西可能丢失的五种方式交叉，构成三十个单元格，每个单元格要么对应一个威胁类别，要么给出不在范围内的理由，要么明确标为*未解决*。十九个单元格已覆盖，三个不在范围内，五个不适用，三个未解决并照此公开：针对费用计价币种的骚扰攻击、滞留零头使回收不划算，以及调用者遇到三种可触达的编译器 panic 之一而不是一个有名字的拒绝。所有未解决的单元格都不构成通向他人资金的路径。

### §14.2 恶意钩子：三层防护，最便宜的先行

钩子是在 Router 正在执行的结算内部运行的任意代码，而天真的防御——问它将要做什么——根本不算防御，因为恶意钩子会撒谎或重入。取而代之的是三层彼此独立的防护，按最便宜、最确定者先运行的顺序排列；它们限定的是对 delta 的改动，而它们触及不到的那一项残余——不改动 delta 的钩子覆盖其动态费用（§5.4）——则改由 Φ 与调用者的最低值来限定。

**第 1 层——权限位存在于地址中，而地址不会撒谎。** V4 把钩子的权限编码在其自身合约地址的低 14 位中；这些位在部署时由 CREATE2 salt 固定，PoolManager 自己在调用钩子之前也会检查同样的位，因此钩子不可能拥有其地址未声明的权限。恰好有两个位允许钩子修改兑换记账，Router 在任何代币移动之前用一次 AND 屏蔽它们（`hookAltersDeltas`）：

$$
\left(\mathrm{uint160}(\mathrm{hook})\ \&\ \mathtt{0x3FFF}\right)\ \&\ \left((1 \ll 3) \mid (1 \ll 2)\right) \ne 0 \;\;\Longrightarrow\;\; \text{leg refused, } \mathtt{RouterE(9)}
$$
^e18

不调用任何不可信代码，没有可以欺骗的对象；要想规避，就需要一个其地址位与 PoolManager 自身强制规则相矛盾的地址。代理可以替换其逻辑的每一行，却仍然得不到其地址从未拥有的任何一位——这就是为什么这项拒绝处于投影距离零（§15.9），而它下面的 codehash 固定则不是。

**第 2 层——允许列表，默认关闭，并固定代码。** 位干净的钩子仍可能恶意回滚以进行骚扰或消耗 gas，因此只有当 V4 池的钩子被策展人列入允许列表时，该池才可路由，并且 Hub 在纳入时固定钩子的 codehash：运行时代码之后发生变化的钩子会被自动暂停而不被驱逐（`isHookLive` 为 false），只有重新纳入才会恢复——放弃控制后，对于任何代码发生变动的钩子，这项权力都会被拒绝。固定的局限在强制位置就已写明：它绑定的是运行时代码，因此能捕捉重新部署或直接改动，却捕捉不到在自身运行时代码保持逐字节不变的情况下替换实现的委托代理，因为 EVM 不给合约任何读取另一合约存储的途径。是否纳入可升级的钩子，是这项固定无法替代的人为判断。不依赖它的其他各层不受影响，照样成立。

**第 3 层——路由根本不会被展示。** 投影算子 Ξ 在排序之前（`_topKPools`）就把钩子会改动 delta 的池子从 Solver 的候选集中移除，Hub 的读取通道也只提供存活的钩子；触及不可纳入钩子的路由不参与最大化。一条路由形态规则使其完整：规范顺序，作用于整条路由——钩子运行之后，绝不会再执行任何无钩子的分支（§11.4）。

![FIG-11 — 对抗恶意钩子的三层防护，最便宜的先行：地址位掩码（不调用任何不可信代码）、带 codehash 固定的允许列表（默认关闭）、投影算子 Ξ（路由无法被表示）。每一层应对一种不同的能力；残余风险——一个干净且已列入的钩子通过回滚浪费 gas——已被点名。](https://blazephoenix.xyz/whitepaper/figs/zh/fig-11.png)

要击穿这套防护，需要一个不带任何 delta 位、在允许列表上保持不变、却仍能颠覆结算的钩子——就 delta 改动而言，第 1 层诉诸 V4 自身不可变的强制规则，排除了这种组合；§5.4 的费用覆盖残余仍然存在，由底线来限定。残余风险已在表中写明：一个已列入允许列表、不改动 delta 的钩子仍可能在兑换中途回滚，浪费尝试所花的 gas。筛选机制唯一的杠杆也已点名：被筛选的钩子之所以绑定实际执行的兑换，是因为规范的 PoolManager 会逐字回显 unlock 数据，且只回调其 unlock 调用者；Hub 的 `setV4Manager` 是一项控制权力，是这一假设所依赖的唯一地址，而一个不诚实的 manager 会让实测输出崩塌，从而让调用者自己的界限拒绝该兑换（`HostileV4Manager` 测试活动）——是有界的，而不是不存在。

### §14.3 有界，而非消除：过时、排序与三明治曲线

报价是关于过去的陈述，而交易发生在未来。帧内求解入口彻底关闭了这一差距中运营方的那一半——路由在执行它的交易内部、根据该区块中的储备推导。剩下的是链自身的那一半：从你签名到你的交易被打包之间，池子可能发生变化。没有人能在合约内部阻止这一点，因为排序在代码运行之前就已决定；声称已消除抢跑的协议，要么把你的交易移出了公共队列、转而信任现在持有它的人，要么描述的东西比听上去要窄。本协议所做的是限定它，两次且彼此独立：你的最低值把损失限制在你选定的数字上，而 Iron-Law 底线——由 Router 根据实测冲击和最后一跳的帧内报价重新推导，而不是根据攻击者或路由提供的任何东西——又以协议自身的名义再限制一次。

这一界限是从攻击者一侧测量的（`test/regime/SandwichCurve.t.sol`）：受害者的路由和底线在报价时固定，与待处理交易一样；攻击者先于受害者交易池子深度的一部分，受害者执行，攻击者再反向交易回来。交易场所是恒定乘积交易对——所有三明治模型都使用的形态——因此这条曲线是底线本身的属性。在占深度 1 % 的交易上（每侧 1,000,000 中的 10,000）：

| 攻击者推动 | 受害者 | 受害者相对报价的损失 | 攻击者往返收益 |
|---|---|---|---|
| 深度的 0.1 % | 结算 | 0.47 % | +13.9 |
| 0.5 % | 结算 | 1.26 % | +68.9 |
| 1 % | 结算 | 2.22 % | +136.7 |
| 2 % | 结算 | 4.12 % | +268.7 |
| 3 % 及以上 | **拒绝** | 0 | −174.5 … −544.9 |

![FIG-12 — 从攻击者一侧看的三明治曲线：按先于受害者推动的深度比例，绘出受害者相对报价的损失与攻击者的往返收益；拒绝边界在 3 % 附近，向上封闭。](https://blazephoenix.xyz/whitepaper/figs/zh/fig-12.png)

在每一个点上断言的保证是：一个完成结算的受害者，收到的金额永远不少于报价时证明的底线，因此损失受限于已证明的报价与已证明的底线之间的距离；而拒绝区域向上封闭——越过边界后，每一次更大的操纵都会被拒绝，攻击者只能自己守着被他推动的价格。值得引用的数字是最后一个完成结算的行：底线把三明治能从一笔 1 % 交易中拿走的部分限制在其约 2.7 %，一旦要拿得更多，就把攻击者的交易变成亏损。帧内路由还增加了一种更安静的威慑：不存在预先公布的路径供搜索者研究，因为路径在执行它的区块之前根本不存在。宽松的最低值是一种邀请；严格的最低值是本节中唯一属于你、也最有效的控制手段。

### §14.4 恶意交易场所

交易场所的病态行为有专门的矩阵（§15.5）：十种异常行为——什么都不付的池子、只付一半的池子、返回 64 KiB returndata 炸弹的池子、在读取或兑换时耗尽全部 gas 的池子、`decimals()` 永不返回的代币、被触发两次的支付回调、在付款前重入 Router 的池子、会回滚的 `slot0()`、用其他代币上的池子作答的工厂——与 calldata 入口和求解入口交叉，20 个单元格中 20 个要么以交付金额等于余额差、Router 上不留任何资产的方式结算，要么以我们自己的选择器拒绝。耗尽全部转发 gas 的兑换，是唯一一个调用者无法替被调用者决定的单元格；交易整体回滚，用户的余额不受影响。Core 对交易场所进行的每一次受守护读取都被限制在 `GAS_CAP = 100,000` gas，因此在*读取*时耗费 gas 的场所只会造成有界的成本并被丢弃，而不是致命的。

### §14.5 恶意前端

在迄今构建的每一个聚合器上，最低值都由界面提议，而草率的界面会提议得很糟——没有合约能知道你本来会选什么。合约能做的是让提议可以被证明：每次兑换都会永久地、在链上发出 `ExecutionProof`——所用的报价、交付的金额、应用的底线——因此任何界面的执行质量都是一份公开的、逐笔交易的记录，任何人都可以审计，包括你自己。一个持续提议糟糕最低值的界面，会把对自己的起诉书写进事件日志。让这一机制完整的防御是一个习惯：签名前看一眼最低值；那是唯一完全属于你的字段。

### §14.6 恶意密钥能做什么、不能做什么

放弃控制之前，管理密钥是存在的，诚实的描述方式是按能力来写，并假定持有者是恶意的；权力的完整列举见 §16.4。

**恶意的 Router 密钥能做的：**更改费用去向（`setTreasuries`）；暂停兑换（`setPaused`）；重新指向原生入口与 Permit2 入口所调用的 WETH 和 Permit2 合约（`setWeth`、`setPermit2`），这使这两个入口的可信程度仅与所设地址相当；排队并在 48 小时后执行对滞留在 Router 中代币的救援（`queueRescue`、`executeRescue`、`RESCUE_DELAY = 48 hours`，由 `RescueQueued` 在链上公告）。**它不能做的：**改动费率、分配比例或底线，因为它们是没有设置函数的编译期常量；拿走本金，因为没有代理，没有升级路径，没有 `selfdestruct`，用户资金对 Router 没有常设授权，且 Router 静止时不持有任何资产——能做到这些的函数不是被禁用了，而是根本不存在。

**恶意的 Hub 密钥能做的：**列入一个交易场所或钩子（`addFactory`、`allowHook`），注入池子（`seedPool`，通过运营方席位），暂停注册表的学习（`setPaused`），重新指向 Hub 所认定的 Router、Solver 和 Quoter（`setRoles`），以及重新指向 V4 manager（`setV4Manager`，筛选机制唯一的杠杆）。**它不能做的：**给成交错误定价，因为注册表只决定能看到什么（§9.6）——恶意列入所能触及的最远处，是报价与*你的最低值*之间的差距；本金够不着，你的滑点容忍度却够得着，这又是一个由你严格设定最低值的理由。

### §14.7 单向门

管理权限以不可逆的方式终结，写在字节码里，而不是靠承诺。Hub 和 Router 都公开 `renounceControl`，且二者在暂停状态下都拒绝被调用（`RouterE(2)`、`HubE(2)`）：一个先暂停后放弃控制的协议，将处于一个谁也不想要、谁也离不开的终止状态，而暂停之所以值得做，恰恰是因为控制权被保留下来用于行动。放弃标志在每个合约中恰好只有一处被写为 `true`，没有任何一处被写为 `false`，因此已部署字节码中没有任何函数能重新打开这扇门——这就是“我们不会”与“我们不能”的区别。

什么关闭、什么保持开放，是逐项列举的，而不是概括的。在 Router 上，`onlyControl` 之下的一切都终结：`setAdmin`、`setTreasuries`、`setPermit2`、`setWeth`、`setPaused`、救援路径——金库、连线和暂停标志永久冻结在当前值，Router 在这一固定配置下继续执行兑换。在 Hub 上，**控制层**终结：`setRoles`、`setOperator`、`setPaused`、`setV4Manager`、`removeBridge`，以及钩子的*移出列表*。**策展层**保留下来，而且只能让注册表增长：`addFactory`（放弃控制后，拒绝任何运行时代码已变动的工厂，或任何会变成询问行的推导行）、`addBridge`（只能添加，最多三个，幂等）、`allowHook(h, true)`（拒绝代码已变动的已列入钩子）；现有的运营方席位保留 `seedPool` 和 `addV4`，且不能授予新的席位。放弃控制后的恶意列入无法抽干资金：池子在报价时和执行时都会被验证，并受底线和调用者最低值的限定。注册表继续通过交易来学习。任何人在谈到本协议时重复“已放弃控制”，都应该能说出哪些门仍然开着——纳入、桥接币、钩子列入、经策展的注入——以及哪些门已经关闭：每一项能改变去向或冻结的权力。

### §14.8 这一模型对你的要求

协议关闭了合约能关闭的：地址伪造、回调冒充、记账伪造、恶意钩子、算术问题。它限定了任何合约都无法消除的：过时与排序，靠你的最低值和底线来限定。对于它连限定都做不到的，它公开证据：代替你提议糟糕最低值的前端。每一行最终都汇聚到同一个字段。每一次都亲自、审慎地设定你的最低值——它是本节中唯一一项质量不取决于任何人的能力、只取决于你自己的保护。

## §15 验证体系的实测

*通俗：*这里的每个数字都与其测量所依据的分母并列给出，都可以由脚本或指名的 `forge` 命令从一份干净的检出中重新计算（附录 C），并且随后注明它不能证明什么。*精确：*被测的代码树是 `8949a9d` 处的 `main` 及成为它的那个分支，采用发布配置（`optimizer_runs = 300`、`via_ir`），日期 2026-09-05。

### §15.1 测试套件的数字

| 项目 | 数量 | 计数方式 |
|---|---|---|
| 已声明的测试 | 236 个 `.t.sol` 文件中共 1,609 个 `test*` / `invariant*` / `check*` 函数 | 对 `test/` 执行 `grep` |
| 发布配置下全绿（不含分叉套件） | 1,320 个中 1,319 个通过 · 0 个失败 · 1 个跳过 | `forge test --no-match-path 'test/fork/**'` |
| 真实流动性上全绿 | 分叉通道 39 个套件、五条链上 119 / 119；另加 §12 的三个 Base 实链测试 | 使用归档 RPC 运行 `forge test --match-path 'test/fork/**'` |
| 有状态不变量 | 14 个测试战役中的 43 个 `invariant_*` 函数 | `grep -rc 'function invariant_' test` |
| 精选变异体，全部被消灭 | 268 / 268 | `.github/scripts/mutants.py`；`check_targets.py` |
| 制度覆盖数组 | 强度 2：63 行，覆盖全部 258 个二元组 · 强度 3：168 行，覆盖全部 1,636 个三元组 · 总计 5,184 种组合 | `covering_array.py --check` |
| 交付尺寸（运行时字节；EIP-170 上限 24,576；项目闸门 24,000） | Hub 23,648 · Router 23,781 · Solver 19,686 · Quoter 11,429 · Core 6,442 | `FOUNDRY_PROFILE=release forge build --sizes` |

### §15.2 证据链与精选变异守卫

一个属性的价值，取决于从威胁到“属性一旦被破坏就会失败的东西”之间最短的那条路径：`threat → property → guard → test → mutant`。守卫以符号命名，测试以名称命名，变异体以它所改动的确切行命名；三者中任何一个离开代码树，构建即失败。套件中每个回归测试都至少被看到失败过一次，且失败原因正是它命名所指——每个修复都附带一个在没有该修复的代码上为红的测试。

变异守卫包含 268 个手写变异体，每个都把一行确切的源码与唯一一个在该行被改动后必须失败的测试配对——删除一个守卫、在决定拒绝的边界上翻转一个比较、放宽一项授权、把一个错误码与其相邻错误码互换。三个特性使它成为守卫而非分数：配对测试先在未变异的代码树上运行并确认为绿；被优化器消除的变异——运行时字节码完全相同——报告为*惰性*，绝不算作被消灭；一个耗时一秒的静态检查验证每个变异体仍然恰好指向一行。203 / 203 被消灭。这个数字是相对于*这份*登记册的充分性：饱和的分数是下限，而不是上限。

### §15.3 瞄准不变量的变异体

在 2026-09-05 之前，没有任何精选变异体把有状态不变量指定为必须因它而失败的测试。14 个测试战役中的 43 个 `invariant_*` 函数全部为绿，却从没有人问过其中是否有任何一个能变红：一个处理器从未到达某属性所保护状态的战役，是在空宇宙上为该属性作证，而从外部看，它与真正到达该状态的战役毫无二致。测量方法与守卫相同，只是对准了各个战役：在源码中改动一个守卫，用同一个种子运行全部不变量，记录哪些察觉到了（`docs/assurance/invariant-mutants.json`）。

| 变异体 | 它移除了什么 | 察觉者 |
|---|---|---|
| 最终转账少付一 wei | 不持有任何余额 | `RouterHoldsNothing`、`routerHoldsNothing`、`HoldsNothingBeyondTheSeed` |
| 协议费用翻倍 | 费用上限 | `FeeNeverExceedsProtocolMax` |
| 输入侧费用从未被收取 | 费用下限 | `FeeNeverEscapes`、`DeliveredNeverBelowUserMinOut` |
| 两侧都收取费用 | 一项费用、一侧收取 | `FeeIsChargedOnExactlyOneSide` |
| 每笔费用的 30 % 流向死地址 | 守恒 | `conservationA/B/C/H`、`TokenConservation`、`LedgerConservationA` |
| 分支交易对守卫放行了交易对错误的分支 | 同质的跳 | `DivergentLegNeverSettles`、`HoldsNothingBeyondTheSeed`、`StrandedMoneyIsNeverSwept` |
| `whenLive` 不再检查 `paused` | 暂停 | `PausedRouterNeverSettles` |
| 重入锁不再拒绝 | 锁 | `reentrancyBlocked` |
| 协议底线减半 | 底线 | `DeliveredNeverBelowTheProtocolFloor` — 于 2026-09-05 闭合 |
| `MAX_SLOTS` 变为 17 | 注册表上界 | `neverExceedsMaxSlots` |
| 移除注册时的交易对证明 | 交易对真实性 | `ActiveEntriesTradeThePair` — 于 2026-09-05 闭合 |
| 输入残余清扫忽略其基线 | 滞留资金 | `StrandedMoneyIsNeverSwept`、`HoldsNothingBeyondTheSeed` |
| 桥接残余清扫忽略其基线 | 滞留资金 | 同上两个 — 于 2026-09-05 闭合 |
| 输出测量忽略其基线 | 滞留资金 | 同上两个 |
| 扣费后的 `userMinOut` 检查减半 | — | 按设计存活：这是一个回归哨兵，在没有转账收费（fee-on-transfer）输出代币的战役宇宙中不可达；有两个单元变异体监视它 |

![FIG-13 — 瞄准不变量的变异体：十五个源码变异对四十三个有状态不变量，每个变异体使哪些不变量变红，2026-09-05 通过为战役补上所缺动作而闭合的三个，以及按设计存活的那一个哨兵。](https://blazephoenix.xyz/whitepaper/figs/zh/fig-13.png)

十五个中有十一个在首次测量时即被察觉；二十个不同的不变量名称至少变红过一次。四个存活者中的三个在同一天被闭合，办法是给战役补上它所缺的动作——在该交易对名下提供外来池、在预先注入的中间余额上走两跳路由、一头巨鲸在过期路由执行前把池子朝不利于已报价路由的方向推动 0–8 %——每一项都在去掉其守卫时被验证为红；“没有任何观察者的守卫有两个”正是这次测量要打印的数字，而它现在是零。十五个中有十四个被察觉；这十四个守卫条目都已与因它们而失败的不变量配对。一个内含无人监视守卫的全绿套件，正是本代码库两次有记录的回归的共同形态；能找出这种守卫的测量，如今在战役所声称覆盖的每个守卫上运行。

### §15.4 制度覆盖数组

覆盖率准则索引的是代码；变异索引的是注入的故障；两者都不索引*测试夹具*在调用前所固定的状态。这类因子共列举了十个——场所族（V2、V3、Solidly）、跳数（1–3）、每跳分支数（1–2）、输入代币是否为已注册桥接币、中间代币是否为桥接币、转账收费形态（无、仅拉取时、每次转账）、输入代币的小数位（18、6）、入口（calldata 路由、交易内求解、Permit2）、控制（在线、已放弃）以及交易对是否已满——共 5,184 种组合。`covering_array.py` 生成这样的数组：每一对（强度 2）或每三元组（强度 3）因子取值都至少出现在一行中；每行是一个夹具，经由同一个测试装置（`test/regime/RegimeHarness.sol`），只有一条断言：兑换完成结算，交付量等于接收方余额的变化量，不低于 Router 发出的底线，且 Router 上不留任何余额——或者以我们自己的选择器被拒绝。panic、外来选择器、交付不足或滞留余额属于第三种结果，该行即失败。

| 强度 | 行数 | 覆盖的元组 | 已结算 | 被拒绝（我们的） | 不可构造 | 第三种结果 |
|---|---|---|---|---|---|---|
| 2 | 63 | 258 个二元组 | 53 | 4 | 6 | 0 |
| 3 | 168 | 1,636 个三元组 | 158 | 10 — `SolverE(5)` ×7、`RouterE(13)` ×3 | 0 | 0 |

![FIG-14 — 制度覆盖数组：在十个因子的 5,184 种组合上，强度 2（63 行）与强度 3（168 行）每个生成行的结果——已结算、以我们的选择器拒绝、不可构造、第三种结果。](https://blazephoenix.xyz/whitepaper/figs/zh/fig-14.png)

这些拒绝来自规划器找不到可构建的桥接路径，以及执行器在仅含集中流动性的路由上拒绝收税代币；强度 2 下无法构建的六行（仅拉取时收税的代币没有六位小数形式）逐一按名称列出，并计入分母。不在数组中的族——V4、原生 V4、Algebra、原生入口、钩子（hook）——在 `regimes-covering.json` 中注明。数组的首次运行把一个对等性测试只钉住了一侧的框架明确化：当费用从输出扣除时，Router 强制执行的底线等于证明底线；当费用从输入扣除时，它位于 $[\mathrm{attested} \times (1 - \mathrm{fee}), \mathrm{attested}]$ 之内——如今两种框架都在每一行上断言。生成的文件在 CI 中与其生成器核对，因此数组不会偏离它声称覆盖的因子。

### §15.5 恶意场所矩阵

代币病态有各自的测试；场所病态却没有成矩阵的测试。`test/regime/HostileVenues.sol` 为每个场所设置一种异常行为，`HostileVenueMatrix.t.sol` 按覆盖数组的规则把每种异常与 calldata 入口和求解入口交叉组合：

| 场所 | calldata 入口 | 求解入口 |
|---|---|---|
| 什么都不付 / 只付一半 | 拒绝 `RouterE(5)` | 拒绝 `RouterE(5)` |
| 储备读取时的 returndata 炸弹 | 结算 | 结算 |
| 储备读取耗尽全部 gas | 拒绝 `RouterE(8)` | 规划器从不选择它 |
| 兑换耗尽全部 gas | 整笔交易回滚，余额不变 | 整笔交易回滚，余额不变 |
| `decimals()` 耗尽全部 gas | 结算 | 结算 |
| 支付回调被触发两次 | 拒绝 `RouterE(6)` | 拒绝 `RouterE(6)` |
| 在付款前重入 Router | 结算；嵌套兑换从未执行 | 结算；嵌套兑换从未执行 |
| `slot0()` 回滚 | 按证明报价结算 | 规划器从不选择它 |
| 工厂返回一个其他代币的池 | 从不列入 | 从不列入 |

二十个单元格中二十个：要么结算，要么以我们的选择器拒绝，绝无第三种结果。最后一行是矩阵首次运行带来的改变——发现过程曾列入一个由策展人准入的工厂所返回的池，执行器在付款的接缝处拒绝了它；如今，被询问到的池必须先证明自己的交易对，发现过程才会列入它（§7）。

### §15.6 规范预言机（oracle）

套件中的每个模拟合约都用 Core 自己的公式报价，因此公式中的缺陷对所有使用这些模拟的对等性测试都是不可见的：预言机本身就是被测对象。`test/regime/CanonicalOracles.t.sol` 包含三个依据各场所公开不变量编写的实现——输入侧收费的恒定乘积、采用池自身不利于交易者舍入的 V3 单 tick 平方根价格步进、用牛顿法求解的 Solidly 稳定曲线——并以它们为基准对 Core 做模糊测试，各 5,000 次运行，先断言方向（Core 承诺的永远不超过场所数学所能交付的），再断言紧密度。

| 族 | 方向 | 实测紧密度 |
|---|---|---|
| Uniswap V2 | Core 从不超过规范 | 精确到 wei |
| Solidly stable | Core 超出曲线的量从不大于求解器自身的最后一步 | 4 wei 以内 |
| Uniswap V3 | Core 超出规范的量从不大于平方根价格的一个末位单位（ulp），折合 $L / 2^{96}$ wei | 对每个满足 $L < 2^{96}$ 的池都低于一 wei |

V3 的界以产生它的那个量来表述——池子把新价格朝不利于交易者的方向舍入，而 Core 只舍入一次，所以两者可能相差 $\sqrt{P}$ 的一个单位——断言的是这个界，而不是样本（在 $L = 10^{30}$ 下，$6.5 \times 10^{34}$ 的输出相差 13 wei）。这些预言机依据规范编写，而非依据场所的字节码；这就是它们的局限。

### §15.7 蜕变关系

用同一公式编写的预言机无法抓住公式本身的错误。蜕变关系转而追问：当输入变动时，输出必须如何*变动*——而场所自己的曲线无需参考实现就能回答这个问题。`test/CoreMetamorphicRelations.t.sol` 针对 Core 的报价数学给出十四条关系，`test/RouteMetamorphicRelations.t.sol` 在一个含真实 Hub 与真实 Solver 的双池宇宙上针对 Solver 的方案给出五条：

| 层级 | 关系 | 含义 |
|---|---|---|
| Core，V2 · V3 · stable | MR1 单调 | 投入更多，产出绝不更少 |
| Core，V2 · V3 · stable | MR2 次可加 | 在同一池上拆分订单绝不会获益 |
| Core，V2 · stable | MR3 无往返获利 | 换入后再在更新后的储备上换回，所得绝不多于投入 |
| Core，V2 · V3 · stable | MR4 尺度等变 | 同时缩放订单与池子，输出按同比例缩放（在舍入范围内） |
| Core，V2 · V3 | MR5 费用单调 | 更高的费用绝不会付出更多 |
| Core，V3 | MR6 方向对称 | 在价格 1.0 处，`outV3` 的两个分支在两个 ulp 内一致 |
| Core，Solidly | MR7 同一性 | volatile 分支*就是* `outV2`，只有一个生产者 |
| 方案 | MR-R1 | 拆分所付绝不少于最佳单池所付 |
| 方案 | MR-R2 | 对 `amountIn` 单调 |
| 方案 | MR-R3 | 在价格带内增加一个池绝不会降低方案 |
| 方案 | MR-R4 | 注册顺序对方案的影响至多为拆分的一个权重单位 |
| 方案 | MR-R5 | 证明底线绝不超过预期输出 |

其中三个界是先测量后写入的，断言中的数字就是机制本身，而不是样本。MR6：在 $L = 8.5 \times 10^{37}$、输入 1,374 wei 时，一个分支报价 1,073,741,823 wei——恰好是 $L / 2^{96}$，即一个 ulp——而另一个报价为零，它的步进被舍入为无，失败即关闭；因此关系表述为两个 ulp，每个分支一个。MR-R1 与 MR-R3：当一个池的价格与另一个相差 $10^{10}$ 倍时，方案所付比单独使用那个离群池少 35 %——深度加权中位数拒绝相信它——因此这两条关系只在价格带所接纳的池上成立，定义域把两个价格保持在 ±4 % 以内。MR-R4：深度权重向下取整到最小值的池，若先注册则作为尘埃分支保留，若后注册则被剔除，使方案变动输出的 $3 \times 10^{-7}$——拆分对最小权重池的保留或剔除取决于其位置，这一点如今已在发现它的地方写明。

### §15.8 N 版本：同一源码在其他代码生成下

套件执行的是一个二进制——发布设置所产出的那个，而 `profile_parity.py` 让套件始终保持在这些设置上。任何其他优化器设置都是由同一源码编译出的另一个程序，而编译器也是一个组件。`test/nversion/` 在另外两个配置下编译 Core 的报价数学——`optimizer_runs` 为 1 和 20,000，其他一切相同——`NVersionCore.t.sol` 把三个二进制并排部署，并在模糊输入上断言结果相等：`outV2`、`outV3`、`outSolidly`、`outSolidlyStable`、`mulDiv`、`mulDivUp`，各在整个输入定义域上运行 3,000 次。该通道首先断言替代字节码与交付的字节码*不同*，因此它不可能靠拿一个程序与自身比较而通过；缺失的构建产物算作失败，而不是跳过。

**三个二进制结果一致。** 发现的问题并不在编译器。该通道首次全定义域运行让*参考实现*回滚了：稳定曲线的拟合检查计算 `max · WAD / b`，而在一个持有不足一个单位代币的池上，这个除法本身就溢出了；第二个逃逸点——巨鲸级输入储备对尘埃级输出储备——通过了不变量检查，却在导数计算中溢出。两者都不是错误的数字；两者都是报价内部的回滚，而 `universalQuote` 是一次库 `DELEGATECALL`，所以一个仅持有一 wei 输出代币的已注册池，就会让 Solver 为其交易对制定的方案整体回退。修复（§6）直接提出那个除法原本所代替的问题，并以先红后绿的方式合入；另一个守卫——对牛顿迭代值设上限——曾被编写，但在两项检查成立后发现任何测试都无法观察到它，于是被移除而不是保留。它的类别正是本仓库首先点名的那一类——失败即开放——由一个并非为寻找它而设计的工具发现。

### §15.9 投影距离

本仓库中确认过的每个缺陷，无论是内部发现还是外部报告，都具有同一种形态：检查观察的是一个对象，而决定行为的却是*另一个*对象。这使得一个拒绝最值得关注的属性不是其复杂度，而是其距离——它所读取的东西与做决定的东西相隔多远。`projection_distance.py` 对五个合约中守护每个 `revert` 的谓词进行分类：常量、immutable、余额变化量，或在当前帧内由其中之一计算出的量，距离为 0；调用者路由中的字段，或在另一合约可变存储中的查找，距离为 1；可以委托自身行为的合约的属性，距离无界。在 99 个拒绝点上：**86 个距离为 0，11 个距离为 1，2 个无界。** 两个无界点都是 `EXTCODEHASH` 钉定——一个是被准入钩子的代码，一个是被准入工厂的代码——两者并不对称：对钩子而言，残余风险由钉定未涵盖的地址位封闭（§14.2）；对工厂而言则没有对应手段，残余风险由池准入、每分支底线和用户最低值共同限定，因此损害是路由质量下降而非资金被抽干，这一点已在该位置注明。这一筛查的局限：它只读取一个谓词，看不到某个值已在三层调用帧之外被约束；一个由调用者声明、同时又是池选择器的字段之所以距离为 0，仅仅因为一次赋值把两者绑定在一起，而这次赋值由 `test/V4SievedHookIsTheExecutedHook.t.sol` 钉住。

### §15.10 证据独立性、共享量登记册与构建产物

对于每个承重守卫，该体系记录存在多少条*独立*确认——按来源、预言机、工具、环境和方法论划分——并报告其中的最小值，因为证据链会在最薄弱的环节断裂；承重属性至少由两条不共享任何假设的途径确认。共享量登记册（`SHARED_QUANTITIES.md`）列举每个拥有不止一个生产者或消费者的量，陈述它所回答的*问题*，并对绑定各副本的方式分级——`SINGLE`、`PINNED`、`WEAK`、`OPEN`、`UNVERIFIED`——同时有一条 CI 规则：若某行的测试达不到它声称钉住的对象，就将其降级；关系登记册中每个双生产者量（7 / 7）都由一个指名的测试绑定。此外，被读取的不只是源码，还有编译后的构建产物：绝不能出现的操作码（`SELFDESTRUCT`、`CALLCODE`、`ORIGIN`）；执行器中仍然存在的瞬态操作码，从而确认重入锁没有悄然变成持久存储；调度表中存在每个已声明的函数；五个合约中有三个不产生任何存储写入；交付形态指令流的 88.3 % 经一个可靠下界证明被执行过，该下界在打印结果前须先对一个基准真值合约作出正确分类以完成验证；以及，将一次记录下来的诚实 V2 兑换在发布版 Router 上重放、并在每一步检查操作码，运行了 4,382 条 Router 指令和 407 条 Hub 指令，零不匹配——分别占两个代码段的 28.2 % 和 2.5 %，其余部分是没有任何已记录场景运行过的代码，而不是死代码。

### §15.11 以上一切都不能证明什么

- **不给出正确性的概率。** 关于验证超高可靠性的文献明确指出，测试无法给出这样的概率；本文也不陈述任何概率。
- **变异充分性是相对于这份登记册的充分性。** 它是人工精选的；饱和的分数只是下限。
- **威胁与制度覆盖是对已考虑范围的下限。** 无人命名过的类别和因子，按构造就不在分母之内。
- **§12 的分布基于模拟合约。** Base 实链给出的是可达性，而不是分布。
- **检出率按单个测试计算，每个种子 256 次模糊运行。** 在该预算下漏检的测试，在更大的预算下可能会抓到。
- **本仓库是 V2，而 V2 尚未部署**（§19）。

上述每个工具都在打印其数字之前经过校准：先针对一个已由其他途径知晓的缺陷运行，若漏掉则加以修正——一个文本匹配器因为匹配了注释中的文本而把文档当作行为；一个覆盖率正则没有考虑 call-option 代码块；一个对应项搜索的模式列表是空的。一个工具在找到已知实例之前毫无价值；没有搜索的结论是空洞的；凡由编译器决定的东西都要测量，绝不估算。

据我们所知，没有其他公开的 DeFi 代码库发布过以下任何一项：带有逐变异体消灭测试和惰性变异报告的、经精选并命名的变异守卫；带有降级 CI 规则的共享量登记册；瞄准其有状态不变量并公布存活者的变异体；在单一断言下覆盖其制度因子的强度 3 覆盖数组；对其报价数学的 N 版本测试；关于其报价如何老化的实测曲线；或其自身费用变异体的检出率及置信区间。这些构建产物都在仓库中；如果你发现了先例，那么这一说法就是错的，我们很希望知道。

## §16 架构与尺寸

*通俗：*五个合约，其中一个是纯数学，被另外四个导入，且任何一段数学都不会被定义两次。*精确：*Core 是一个无状态库，没有存储、没有所有者、没有升级路径；Hub、Solver、Router 和 Quoter 导入它，且都不重新定义任何原语，因此对数学的一次审计即可覆盖所有使用者。

### §16.1 五个合约：各自持有什么，各自可以调用什么

| 合约 | 持有 | 可调用 | 写入持久状态 | 尺寸（运行时字节） |
|---|---|---|---|---|
| **Core**（库） | 无——只有 pure 与 view 函数：Ω、𝒟、Φ、Ψ、单槽（Monoslot）编解码器、安全转账、`mulDiv` | 池与代币，只读，每个受守护的 `staticcall` 上限为 `GAS_CAP = 100,000` | 从不——无 `tstore`，无 `sstore` | 6,442 |
| **Hub** | 注册表（每个池一个单槽，每个交易对 ≤ 16 个）、工厂行（≤ 16）、桥接币（≤ 3）、带 codehash 钉定的钩子允许列表、V4 条目、角色；采用 ERC-7201 命名空间 | 池与工厂，只读，经由 Core；通过 `extsload` 读取 V4 PoolManager | 在 `recordSwap`（仅限 Router）时、在准入与配置时 | 23,648 |
| **Solver** | 无——仅 `view` | Hub（注册表读取、发现），经由 Core 访问池 | 从不 | 19,686 |
| **Router** | 管理员、国库、`permit2`、`weth`、`paused`、`controlRenounced`、救援队列；**静止时不持有任何代币余额** | 输入代币、路由中的池、输出代币、Hub（`isBridgeToken`、`isHookLive`、`recordSwap`）、Solver（仅 `swapBestExactIn`，`view`）、V4 所需的 WETH 与 PoolManager、其入口所需的 Permit2、国库、接收方——绝不调用由调用者提供的目标 | 自身配置；每笔兑换唯一的外部写入是成功路径上的 `Hub.recordSwap` | 23,781 |
| **Quoter** | 无 | Solver（`view`）、Hub（`isBridgeToken`，只读）、用于 Exact Pass 试运行的池（调用后回滚） | 从不 | 11,429 |

![FIG-15 — 五合约拓扑：Core（纯数学：Ω · 𝒟 · Φ · Ψ）被 Hub（注册表、Ψ 状态、桥接币、钩子钉定）、Solver（路由优化器，view）、Router（原子执行，唯一移动资金的合约）和 Quoter（预览，view 与试运行）导入。箭头表示调用；每笔兑换唯一一条指向存储的实线箭头是 Router → Hub.recordSwap；Solver 与 Quoter 发出的其余箭头均为只读。](https://blazephoenix.xyz/whitepaper/figs/zh/fig-15.png)

信任是单向的。Hub 只信任 Router 调用 `recordSwap`（`onlyRouter`），不信任其他任何人；Router 在路由所需的三件事上信任 Hub——这个代币是不是桥接币、这个钩子是否在线，以及注册写入——而在任何为交易定价的事情上都不信任它。Solver 只把 Hub 的注册表当作一份待测量的坐标列表来信任。Quoter 把 Solver 的方案视为建议，并对照池本身重新为集中流动性分支定价。没有任何东西信任 calldata：路由到达 Router 时，只是一个陌生人的声称。

### §16.2 一笔兑换的生命周期

![FIG-16 — 一笔兑换的生命周期：`previewAndEncode`（view）→ calldata → 入口 → `_execute` → 交易场所 → 结算，每一步的检查都以其拒绝码命名：入口处的最低值与截止时间；跳的形态与连续性；测量到账量；每跳的重新缩放、若为收费跳则收费、每分支底线与覆盖闸门、跳汇总；清扫；总输出；路由底线 Φ；如有则收取输出侧费用；在接收方处测量交付；`userMinOut`；费用账本；每个已执行分支的 `recordSwap`；`ExecutionProof`。](https://blazephoenix.xyz/whitepaper/figs/zh/fig-16.png)

1. **预览**（链下，免费）：`previewAndEncode` 运行 `findBestRoutePlan`——注册表，若不新鲜则进行发现；Ξ；Ψ 排序；探测；价格带；分配；钳位；拆分闸门；证明底线——并返回 `Preview` 与 calldata。交易者根据自己的价格预期设定 `userMinOut`。
2. **入口**：`swapExactIn`（或其同类函数）检查截止时间（`RouterE(4)`），拒绝为零的最低值（`RouterE(10)`），拉取输入并测量变化量。
3. **`_execute`**：跳数、每跳分支数与跳的连续性（`RouterE(3)`）；费用扫描；基线仅生成一次。
4. **每一跳**：按测得的到账量重新缩放；若为收费跳则收费（穷尽制度下则每跳都收）；每个池只读取一次，获取数量、价格影响与报价；按其类型所选的形态执行每个分支（未知类型为 `RouterE(8)`，改变差额的钩子为 `RouterE(9)`）；带覆盖闸门的每分支底线与跳汇总（`RouterE(5)`）；回调只向已承诺的池付款（`RouterE(6)`）。
5. **清扫**：高于各自基线的未花费输入与桥接残余返还给付款方。
6. **结算**：以变化量计算总输出（为零则 `RouterE(8)`）；由实测价格影响与集中度得出 `floorBps`；以最后一跳的帧内报价和三方最大值计算路由底线（`RouterE(5)`）；直接路由进入桥接币时收取输出侧费用；转账，在接收方处测量交付，对交付量检查 `userMinOut`（`RouterE(5)`）；费用账本（`RouterE(15)`、`RouterE(16)`）。
7. **唯一的写入**：对每个已执行分支调用 `Hub.recordSwap`，使用实测数量；随后发出 `ExecutionProof`、`Swap` 与 `Fee` 事件。只要任一检查拒绝，就不写入任何内容；这笔交易，连同其中每个池的兑换，从未发生过。

### §16.3 对照 EIP-170 的尺寸

| 合约 | 运行时字节 | 距 24,000 字节闸门的余量 | 距 EIP-170（24,576）的余量 |
|---|---|---|---|
| Router | 23,781 | 219 | 795 |
| Hub | 23,648 | 352 | 928 |
| Solver | 19,686 | 4,314 | 4,890 |
| Quoter | 11,429 | 12,571 | 13,147 |
| Core | 6,442 | 17,558 | 18,134 |
| 合计 | 84,986 | | |

![FIG-17 — 五个合约的运行时尺寸，对照项目的 24,000 字节闸门与 EIP-170 的 24,576 字节上限，在发布配置下测量；已部署的 V1 router（14,624 字节）作为参照。](https://blazephoenix.xyz/whitepaper/figs/zh/fig-17.png)

闸门在套件内部断言（`DeployedSizeGate`），所用配置与套件运行的配置相同，而 `profile_parity.py` 保证该配置与发布配置一致——一个测试链上无法接受的二进制的套件，测的是错误的对象。尺寸靠测量，绝不估算：一个曾被估计为几十字节的守卫，实测却有几百字节，因为所选的写法延长了某个变量的存活范围。Router 和 Hub 离上限只有几百字节，这就是为什么 §9 的交易对证明只花 179 字节，而 §6 的稳定曲线修复比它所替换的代码还*小* 35 字节：每增加一个字节，都要以删除一个字节来支付。

### §16.4 攻击面，逐项计数

攻击面就是对手能写入什么、合约持有什么、它调用谁，以及谁对它握有权力。在这里，每一项都是可计数的量。

**调用者能写入什么。** 路由是一个有类型的结构——至多 3 跳 × 5 个分支，每个分支十个字段（`pool`、`hooks`、`kind`、`fee`、`tickSpacing`、`zeroForOne`、`stable`、`amountIn`、`expectedOut`、`auxId`）——没有任何字段指定调用目标或携带 calldata 数据块。`docs/assurance/fields.json` 对每个能到达状态、事件或守卫的调用者可写字段进行分类，共 23 个：

| 类别 | 数量 | 含义 | 示例 |
|---|---|---|---|
| **已确认** | 14 | 执行读取该字段，*并且*有检查将其与一次观测进行比较 | `leg.kind` 由池的形态重新推导（Hub `recordSwap`）；集中流动性池上的 `leg.fee`，由池自己回答；`leg.amountIn`，按测得的到账量重新缩放；`leg.expectedOut`，由覆盖闸门抬升；`hop.tokenIn`/`tokenOut`，对照池自身的 `token0`/`token1` 设闸；V4 上的 `leg.hooks` 与 `leg.auxId`，它们进入被执行的池 id |
| **导向型** | 5 | 该字段引导一次代币移动，因此错误的值惩罚的是调用者自己，无需单独检查 | 交易对型与集中流动性场所上的 `leg.pool`（代币被推送给它）；V4 上的 `leg.zeroForOne`（方向错误会在管理器的记账中失败即关闭）；`route.singleOutFloor`（单调——只能收紧）；建议性路由字段（`totalOut`、`estGas`、…），无人读取 |
| **仅声明** | 4 | 它到达状态、事件或守卫，但没有任何东西观测它——每一项都记录了理由 | V2 交易对上的 `leg.fee`（交易对不暴露 `fee()`；受 100 bps 上限约束，且报价与执行使用同一值，因此两者不会分歧）；非 V4 分支上的 `leg.hooks`（只影响钩子置后的排序；说谎只会让调用者损失自己的路由）；`Volume` 事件中公布的 `leg.expectedOut`（被消费同一字段的每分支底线限制在约 +25 % 以内；链上没有消费者）；`leg.stable`（Hub 在注册时测量 `stable()`，两个消费者读取的是同一个声明） |

注册表的排序、协议底线和费用基数只由已确认的量计算。Hub 确认 `kind`；Router 确认数量、代币和集中流动性费率；推导过程按构造确认 V4 字段。

**Router 在交易之间持有什么。** 零代币余额——`INV-1`，由各战役中的 `invariant_RouterHoldsNothing`、`invariant_routerHoldsNothing` 和 `invariant_HoldsNothingBeyondTheSeed` 断言，并由四个守卫变异体监视（少转一 wei 的转账，以及三个基线各自被移除）。费用在兑换内部流向国库；残余在兑换内部返还给付款方；唯一可能停留在 Router 中的是误转入的资金，48 小时救援机制正是为了返还它而存在，且每笔兑换的基线都将其排除在支付之外。五个合约中的三个——Core、Solver、Quoter——根本不产生任何存储写入。

**一笔兑换调用谁。** 一笔兑换的交互对象构成一个由八类组成的封闭集合：输入代币；输出代币；路由所列的池（至多 15 个）；Hub；Solver，仅通过 `swapBestExactIn` 且仅作为 view；WETH 与 PoolManager，仅用于 V4 与原生分支；Permit2，仅通过其入口；国库与接收方。不存在第九类：执行器不接受任何由调用者提供的调用目标（SOK-ARBITRARY-CALL），而是从一个由注册表所持类型选定的封闭形态集合中分派与场所的交互。每次受守护的读取上限为 100,000 gas。一笔兑换的确切指令数是被记录而非被断言的：在发布版二进制上，一笔诚实的 V2 兑换执行 4,382 条 Router 指令，且每一步都检查了操作码（§15.10）。

**谁握有权力。** Router 上有九个控制函数，Hub 上有六个，每一个都在 §14.6–§14.7 中列举，并说明它能触及什么、不能触及什么；没有一个能移动本金、费用、拆分或底线；它们全部终结于 `renounceControl`，之后留存的只有由四个函数组成的只增不减的策展人层级，以及已有的运营者席位。没有 `selfdestruct`，没有代理，除 Hub 的一次性 `initialize` 外没有初始化器，构建产物中唯一的 `delegatecall` 是编译器自己生成的、指向公开 Core 库的调用。

**一笔交易要结算，必须存在什么。** §3.1 的预算：无路由服务、无预言机、无求解器网络、无 keeper、无代理——在现有主流设计写着“必需”“常见”或“视情况而定”的地方，这里是五个零。

**计数得出的差异。** 对照一种在链下获取路由并执行通用调用列表、或持有库存的设计：

| 攻击面 | 本设计 | 链下求解的执行器 | 持有库存的场所或路由器 |
|---|---|---|---|
| 能到达守卫的调用者可写字段 | 23 个，其中 14 个对照观测确认，0 个指定调用目标 | 一个 `(target, calldata)` 对的列表：无界，且每个目标都是合约凭调用者一句话就发起的调用 | — |
| 执行器静止时的代币余额 | 0（`INV-1`） | 通常为 0 | 库存本身 |
| 兑换期间写入存储的合约 | 1（`Hub.recordSwap`，每个已执行分支一次写入，仅成功路径） | 视情况而定 | 场所自身的记账 |
| 由谁计算路由 | 链（`findBestRoutePlan`，`view`）或调用者，两种情况都在帧内重新测量 | 服务器；合约只做检查，不做选择 | — |
| 预言机、keeper、代理、升级路径 | 0 | 通常各 ≥ 1 | 通常有一个代理 |
| 能触及本金的特权函数 | 0 | 代理管理员可以替换逻辑 | 视情况而定 |
| 审计者必须阅读的已部署字节 | 84,986，五个合约，全部低于 EIP-170 | 结算合约，外加一个可审计代码行数无从得知的服务器 | — |

这一比较是计数得出的，而非辩论得出的：差异在于有界、有类型、经确认的路由对无界列表；零对库存；一次写入对多次写入；以及由链推导——或由调用者推导、再由链重新测量——的路由，对由服务器推导、链仅做检查的路由。

## §17 实测性能

*通俗地说：*本节的一切都在真实链的分叉上测得——真实的交易场所、由陌生人存入的真实储备、同一份字节码——并如实标注。*精确地说：*一个数字只有在仓库中有公开测试工具（harness）能复现它时才会出现在这里；工具、链和日期都印在它旁边。分叉测量是关于行为的证据，而不是部署记录；部署记录见 §19。§12 与 §15 的测量来自 2026-09-05；本节的测量活动在 2026 年八月进行，其测试工具位于 `test/fork/`。

### §17.1 跨链一致性

同一份字节码在 Ethereum、Arbitrum、Optimism 和 Base 的分叉上运行，适应每条链的交易场所组合——Base 上 V4 之外还有 Aerodrome 和 Pancake，Arbitrum 上有 Camelot，Optimism 上有 Velodrome——没有任何按链修改的代码。选择这四条链，是因为它们合起来覆盖了注册表接纳的每一个交易场所族，所以如果存在按链的特例，它有四次机会暴露出来。在每条链上，两项一致性都对照真实情况进行了测量：对 CREATE2 推导，将 𝒟 计算出的每个池地址与该链自己的工厂对同一交易对和参数报告的地址相比较，并由 `hasCode` 确认每个推导地址上都有字节码；对 Exact Pass，在实时状态上调用交易场所自己的 swap，并把其增量通过 revert 载荷带出，逐链进行，经受住了每个族的回调约定，包括 Algebra 的。两项一致性在全部四条链上都成立，表格所需的“差异”一栏为空。

### §17.2 四条链上的预览 → 交付保真度

这一论点可以直接测量：为一笔兑换报价，执行它，然后比较。`FidelityMatrix` 分叉测试工具在固定区块上对 Arbitrum、Base、Optimism 和 Robinhood Chain 的真实交易对进行报价、执行和结算，并为它触及的每个交易对打印预览与交付的对比；它带有一个 50 bps 的常设警报，因此保真度一旦退化会自行暴露。测量于 2026-08-24：

| 链 | 预览 → 交付 | 同时记录 |
|---|---|---|
| Arbitrum | 每个已执行交易对均为 0–1 bps | Solver 的路由与以 10 % 为步长的穷举双向拆分网格一致 |
| Base | 0–1 bps | 与网格最大值相差在 0.13 bps 以内；真实成交全部计入为 222,000–326,000 gas |
| Optimism | 0–1 bps | 本引擎在 Optimism 上首次经分叉测量的 V4 路由执行 |
| Robinhood Chain | 0–1 bps | 与网格完全一致；该链上首批实测执行 |

该矩阵端到端执行恒定乘积、集中流动性、V4（包括原生资产）和 Solidly 分支。每个已执行交易对的偏差带都是一个基点，背后有 50 bps 的警报；§17.1 中 Solver 与网格的比较是唯一精确到单位一致的结果，我们也如实这样表述。另有两项行为结果：桥接中间币作为元方程的最大化解按交易对自适应选择；一个刻意隔离的交易对返回无路由，而不是一条捏造的路由。

### §17.3 工厂普查

一次交易场所注册是一个声明，而这个声明有它自己的测量工具。普查测试工具（`FactoryCensus`）继承生产部署的连接配置——它通过各链所用的同一脚本进行部署，并有一道相等性闸门，若测试工具与部署出现偏离就拒绝运行。它与该脚本一起位于私有部署目录中，不在公开仓库里，因此下表是报告值，无法从本检出副本复现；与它共享测试夹具和反空洞闸门的公开扫描是 `test/fork/TokenSweep.t.sol`。对每条链上的每个已注册工厂，在固定代币语料上，它报告三列：已注册、持有该交易对的池、赢得该交易对（为获胜路由提供了一个分支）。这些列共享一个分母——跳对（hop-pair），并设有一个明确的“未归属”桶，在全部四条链上测得为零：引擎路由的每个分支都归属于一个具名工厂。

| Arbitrum，88 个跳对 | 持有池 | 赢得交易对 |
|---|---|---|
| Uniswap V4（原生 + 包装） | 67 | 48 |
| Uniswap V3 | 86 | 33 |
| Pancake V3 | 77 | 13 |
| Camelot V3 | 66 | 10 |

一个交易对会计入为其获胜路由提供分支的每个交易场所，因此该列之和可能超过交易对数——这是归属，而不是划分。在 Arbitrum 上，V4 族赢得的交易对比任何其他已注册交易场所都多，包括标准 V3 工厂——这从外部证实了 §5.1 的原生优先探测顺序。普查也是一种修剪工具：一个已注册、持有池子、却在数百个实测交易对中一无所获的工厂，就是退役候选，其定价依据是归属而不是声誉；而且每次扫描都带有反空洞闸门——被报告为有深度的交易对，其报价也必须非零。

### §17.4 Gas

每个数字都可追溯到一个具名测试工具，冷启动与热启动分别报告。

| 测量 | 数值 | 来源 |
|---|---|---|
| 冷求解（首次发现，4 个工厂） | 169,093 gas | `test/fork/DiscoveryColdWarm.t.sol`；`REPORTS.md` |
| 热求解（缓存的 Monoslot，跳过发现） | 132,691 gas | 同一次运行 |
| 热启动节省 | −36,402 gas（−21 %） | 差值 |
| 每增加一个分支的边际成本 | ≈ 28,700 gas | `LifecycleMetrics`（2026 年八月） |
| 经桥接的第二跳 | ≈ 59,000 gas | `LifecycleMetrics`（2026 年八月） |
| 实时 Base 上的 `previewPlan`，冷 / 热 / TTL 过后冷 | 1,524,221 / 1,414,633 / 1,359,925 gas | `test/fork/QuoterGasFork.t.sol`（§12.3） |

![FIG-18 — 通过 ABI 获取一次报价的成本：模拟环境中的 `previewPlan` 与 `previewAndEncode`（发现 vs 新注册表，四十种规模下的均值与离散度），以及实时 Base 上的情况（冷、热、TTL 过后冷）。](https://blazephoenix.xyz/whitepaper/figs/zh/fig-18.png)

有三条结构性解读无需任何测量即成立，因为它们源自架构本身。热启动节省随注册表的广度而非交易规模扩展：冷路径付费的是扫描工厂，而取代扫描的缓存读取无论如何都只是一次 `SLOAD`。分支是边际成本的单位，这正是拆分闸门存在的原因（§10.4）。而跳是昂贵的维度：一条桥接路由必须在池子上赢得足够多，才能抵消它在油泵上的花费。调用者为每笔交易选择自己在这个曲面上的位置——在帧内求解并为搜索付费，或者自带路由而只为执行付费——而 §9.4 的新鲜度闸门把扫描留给协议尚不了解的交易对。一次实时报价的成本是 1.4–1.5 百万 gas 的 *view* 计算，链上无人为此付费。

### §17.5 执行器与同行的对比

没有外部参照的 gas 表格只是自夸，因此执行层在同一分叉、同一区块上，用真实的生产 calldata 做了基准测试：对象是 KyberSwap 的 `MetaAggregationRouterV2`（`0x6131B5fae19EA4f9D964eAc0408E4408b66337b5`），在固定于每条路由构建区块的 Base 分叉上，于 2026-08-22 进行，并以 Paraswap 的报价作为第二个比较对象：Kyber 自己编码的路由从其公开 API 请求，并在其已部署合约上重放，我们的路由在旁边执行，双方的交付都以余额增量测量。测试工具首先自我验证：竞争者的实测交付与其 API 的承诺精确到 wei 一致，因此任何一方的 revert 都无法伪装成结果。按分支计，执行器的 gas 效率比参照高 2.4× 到 10.9×——在最清晰的交易对上，我们四个分支用 322,172 gas，对方一个分支用 879,553，按交易计为 2.7×——所用测试工具（`BenchExec.t.sol`）与捕获的 calldata 一起位于私有目录中，因此这些数字是报告值，无法从本检出副本复现；本检出副本以 `optimizer_runs = 999999` 编译——所以差异来自设计，而非编译器设置；他们的路由器解释由服务器决定的通用调用列表，我们的执行一个类型化结构，而解释是有成本的。在最清晰的交易对上，他们的单分支路由花费 879,553 gas；我们的四个分支花费 322,172。在九个实测交易对上，完全求解的入口与 calldata 入口交付了相同的输出。方法的误差范围也是结果的一部分：报价固定在其构建所针对的区块上，而 API 端的 gas 估计在真实执行测得其中一个低估 148 % 之后被弃用。

### §17.6 字节–gas 汇率 ρ*

调用者应该使用哪个入口——在 calldata 中携带路由，还是让链来求解？一笔交易的成本是仿射且可分离的——$21{,}000 + \mathrm{bytes} \cdot p_{\mathrm{byte}} + \mathrm{gas} \cdot p_{\mathrm{gas}}$——因此 calldata 与执行之间的全部权衡归结为一个标量：**ρ\***，即一个 calldata 字节能换来的执行 gas。在发布配置下用 `test/EquationBench.t.sol` 测得，按整笔交易计，ρ* 从单分支路由的每字节 66.9 gas 到四、五分支路由的 105.5。与之对照的是每条链的实时字节价格，从链自己的费用预部署合约读取——OP-Stack 的 gas 价格预言机、Arbitrum 的 `ArbGasInfo`——无需密钥，也无需第三方数据源。

| 链，价格实时读取于 2026-08 | $p_{\mathrm{byte}}$（gas/字节） | 数据在一次兑换中的占比 | 便宜的入口 |
|---|---|---|---|
| Base | 7.2 | 0.9 % | calldata 路由 |
| Arbitrum | 12.8 | 3.4 % | calldata 路由 |
| Optimism | 33.9 | 14.0 % | calldata 路由 |
| 按 calldata 计价支付数据可用性的 ZK rollup | 243,256 | 99.9 % | 帧内求解——端到端便宜 14× |

当 $p_{\mathrm{byte}} < \rho^{*}$ 时，calldata 入口更便宜；当 $p_{\mathrm{byte}} > \rho^{*}$ 时，帧内求解更便宜。在 OP-Stack 与 Arbitrum 链上，数据项占一次兑换成本的 0.9–14 %，所以钱花在执行上——这正是上文执行器效率产生复利的地方。Router 的四个入口不是一项便利功能；它们就是仿射成本模型，被做成了接口。

## §18 剥到骨头的 DEX

十七节的机制归结为一页。如果你别的都不读，就读这一页。

**一项工作。** 接收两个代币、一个数量、你的最低值、一个接收人和一个截止时间。返回链上公开流动性所能交付的最大输出——或者拒绝，并给出说明原因的代码。不存在第三种结果：在恶意交易场所矩阵中，二十个“场所病态 × 入口”测试夹具中有二十个要么在底线之内结算，要么以我们自己的选择器拒绝（§15.5）。

**五个合约，一套数学。**

| 合约 | 一句话说明它是什么 |
|---|---|
| **Core** | 无状态库：每个交易场所的闭式公式、推导 𝒟、底线 Φ、活力评分 Ψ。只定义一次，由其他四个合约导入。 |
| **Hub** | 通过交易来学习流动性的注册表——并在存储每个交易对之前证明它。它不为任何东西定价。 |
| **Solver** | 根据*实测*的边际输出和深度构建路由与拆分。仅 `view`。 |
| **Router** | 唯一移动资金的合约。测量每一个余额增量，强制执行底线，静止时不持有任何资产。 |
| **Quoter** | 免费预览——与 Router 结算所用的是同一个求值器，因此预览与交付一致。 |

**六类交易场所，四个族。** Uniswap V2、V3 和 V4（包括原生 ETH）、Algebra 动态费率池，以及 Solidly stable 与 volatile 交易对——每一类都由 Core 中的一个闭式公式定价，全部由一个调度器 Ω 处理（§4）。Curve 和 Balancer 已被移除，它们的类型编号永久退役（§4.1）。

**四个入口，一个执行器。** `swapExactIn`、`swapExactInWithPermit2` 和 `swapExactInNative` 接收 calldata 中的路由；`swapBestExactIn` 在链上原子地求解并执行。四者都到达同一个 `_execute`、同样的底线和同一项费用（§11.1）。

**每笔交易下的三道底线。** 每分支底线、跳聚合底线，以及在执行帧内根据实测价格影响重新推导的路由底线 Φ——然后是*你的* `userMinOut`，作用于实际到达接收人的数量。交付值取协议底线与你的底线中较大者（§11.5）。

**一项费用，编译在内。** 0.28 %，在 Router 持有的第一个桥接币上只收一次，向上取整因而永不为零，并且没有任何随报价与交付差距增长的项（§13）。

**它拒绝信任什么。** 宣称的流动性。声明的费率。calldata 中的深度。池子自己关于它交易哪些代币的说法。每一项要么从池子测得，要么在到达共享状态之前由算术推导得出（§7、§9、§16.4）。

**它的代价。** gas：在帧内推导路由比结算一个在别处算好的答案更贵，而 §17.6 按链告诉你哪个入口最便宜。不可变性：缺陷会被公开并给予赏金，但永不修补（§21）。

## §19 部署状态

本文记录的是仓库，而仓库是权威来源：本文与源代码不一致时，以源代码为准。存在两代合约，它们从不混为一谈。

**V1 是链上运行中的版本。** 它是一套不同的、更早的代码库，归档在它自己的仓库中——而不是本仓库的某个早期提交。经 RPC 于 2026-09-04 测量，已部署的 V1 路由器在 Base、Ethereum、Optimism 和 Arbitrum 上是同一个 14,624 字节的合约。`test/fork/DeployedParity.t.sol` 和 `test/fork/DeployedCodehashPin.t.sol` 在 SDK 列出的每个网络上固定 V1 是什么——每个已部署合约的 codehash，记录在 `test/fork/deployed-codehash.json` 中——因此已部署内容的任何变化都会被察觉；它们还断言那些不论哪一代都成立的属性：没有 `SELFDESTRUCT`，没有 `CALLCODE`，没有 `tx.origin` 授权，有瞬态重入锁，运行时大小固定，连接配置有效，以及控制权尚未放弃。

**本仓库是 V2，而 V2 尚未部署。** 本文测量的代码树构建出一个 23,781 字节的 Router，并带有 V1 所没有的外部函数——其中包括原生资产入口、wrap/unwrap 接缝、救援路径和 Permit2 入口。V2 合约被部署到实时流动性的分叉上，并在每次分叉运行中端到端演练（§15.1、§17）。§15 或 §17 中没有任何内容保护已部署的 V1 合约；本文中的每一项主张都是关于处于 `8949a9d` 状态的 V2 的主张。

因此有两项政策保护读者。本文不包含任何合约地址——地址的寿命比引用它们的文档更长，实时地址信息维护在能够更新并经机器检查的地方：仓库的记录，以及网站的验证页面与清单。部署记录有规定的格式——链、地址、部署提交和运行时字节码哈希，在广播时写入，并有一个从干净构建重新推导哈希的验证步骤——这样，当 V2 部署时，每一项地址主张都是算术，而不是信任。

## §20 代币 — BZPX

十亿 BZPX，永久固定，是一个朴素的 ERC-20：18 位小数，无增发路径，无转账收费（fee-on-transfer），无 rebasing，无转账钩子，无暂停或黑名单——六项部署不变量，在连接时对照代币字节码检查。完全稀释供应量自创世起即已知；稀缺性是合约的属性，而不是一项政策。

| 分配 | 代币 | 占比 | 说明 |
|---|---|---|---|
| 市场流动性 | 520,000,000 | 52.0 % | 聚合器路由经过的流通量 |
| 质押排放 | 180,000,000 | 18.0 % | 预留；V4 排放设计见 §25 |
| Airdrop & Bounties | 130,000,000 | 13.0 % | 一个池：原 50,000,000 空投、§21 原 50,000,000 研究资金池，以及从市场流动性转出的 30,000,000 |
| 团队与运营 | 103,000,000 | 10.3 % | 唯一锁定的内部人份额；30 个月线性归属 |
| 合作伙伴与生态 | 60,000,000 | 6.0 % | 集成、交易场所合作 |
| 营销 | 7,000,000 | 0.7 % | 上线宣传 |

**2026 年九月的变化。** 空投与安全研究资金池原是两行，为同一件事向同一批人付费——认真地审读协议并真实地使用它。现在它们合为一行 130,000,000 BZPX：50,000,000 来自空投，50,000,000 来自研究资金池，30,000,000 取自市场流动性，市场流动性因此从 550,000,000 变为 520,000,000。没有从其他任何一行取用，供应量仍然恰好是十亿。

代币合约的链上记录一经公布，即为本表的权威版本。撰写本文时，该代币尚未提供流动性，也没有代币生成事件；链上交易量为零是这一阶段的预期状态，而不是关于代码的信号。

## §21 研究计划与安全记录

在本项目拥有一个名副其实的研究计划之前，独立研究者就以敌意的眼光审读了源代码——无人邀请，也没有任何承诺——并私下披露了他们所发现的问题。本文描述的代码，正是经受住他们审读的代码。他们每人报告了什么、结果如何，都记录在这类记录应在的地方：仓库的 `SECURITY.md` 和 `SECURITY_HALL_OF_FAME.md` 中，紧挨着代码，每一条都可以双向核对。本节记录他们是谁、敌意审读能得到什么报酬，以及它所发现问题的形态。

**研究者。** NetGakarot · duxun · AmanDara1 · amitbhakar · auditor_1b3f2c · siam siddik · Thomas · llen · destinyae · superagent · Mohd Huzaifa · Raditya · bai bo · Josh W · Borutobro · mohaseenkatika · mohaseenbasha · Karan Rathod · Seavia Resources · acit aja · Brian Wahyu · M2000 Slash · Binod Bk · CHARIR ABDELHAMID · 以及一位选择匿名的研究者。已有二十五位研究者获得署名；没有任何报告达到严重（Critical）级别。署名从不打折扣：名字完全按提供的形式公布。

**资金池：Airdrop & Bounties，130,000,000 BZPX——固定供应量的 13 %**（§20）。安全奖励按下列档位从中支取，档位保持不变。

| 严重程度 | 奖励 |
|---|---|
| 严重（Critical）——直接盗取或永久冻结用户资金；可到达的资不抵债状态 | 2,500,000 – 7,500,000 BZPX |
| 高（High）——特定条件下的盗取；系统性地向错误一方支付的再分配 | 625,000 – 2,500,000 BZPX |
| 中（Medium）——恶意干扰（griefing）、临时拒绝服务、可回收的残余 | 125,000 – 625,000 BZPX |
| 低（Low）——低于上述级别的已证实影响 | 最高 125,000 BZPX |

奖励以 BZPX 支付——承诺的是数量和时间表，而不是市场价值——支付在 2026 年十月之后开始，报告现在即进行分级处理。有一条条款是刻意设定的：报告不必打破守恒律也能被评为严重——一种在账目平衡的同时系统性地向错误一方支付的再分配，按盗取定价，因为这正是只有敌意读者才能抓到的那一类问题。

**记录中包含什么，按类别。** 每一项确认的发现都变成了一个具名属性、一个针对修复前代码会失败的回归测试，以及一个该测试必须消灭的变异体；以下各类别各用一句话说明，并引用登记册：

- *同一数量的两个产生者*——规划器与执行器、预览与交付，在两个帧中回答同一个问题（底线的价格影响聚合、预览指定的桥接币与费用锚定的跳、跨两个合约的分支预算、冻结的桥接位与实时谓词）：通过合并为一个产生者或通过具名的一致性测试来关闭，并列为一个带有 CI 规则的登记册。
- *本有测量却由调用者提供的数量*——从 `route.totalOut` 读取的费用基数、从 calldata 写入的注册表费率与钩子、声明而非测量的深度、报告了声明值的公开交易量：通过测量来关闭，并通过 §16.4 的字段分类来关闭。
- *把缺失当作许可*——无法在帧内报价的最后一跳使底线失效、调用者写入零即可关闭的覆盖闸门、把整个族报价为零的空费率列表：通过回退到经证明或实测的数值来关闭，绝不回退到“什么都没有”。
- *钉错了对象*——工厂的推导来源可被代理移动而其 codehash 保持不变、钩子的运行时被钉住而其实现仍可移动：通过在代码无法被钉住之处证明答案来关闭，并在无法关闭之处就地说明残余风险。
- *报价中的失败开放（fail-open）*——稳定曲线的定义域守卫本身在微量输入上溢出，由 N 版本通道发现：以先红后绿的方式关闭，修复比它替换的代码更小。
- *只应用于两个对称通道之一的修复*——这是本代码库首先命名的缺陷特征，反复遇到；如今每一次关闭在合并前都会先搜索其对称的兄弟问题。

邀请才是本节的要点，而且它长期有效：独立读者受到公开邀请，并获得报酬，以数量固定的货币支付。请通过仓库 `SECURITY.md` 中的披露渠道私下报告。

## §22 你必须信任什么，以及无需信任什么

每个协议都自称免信任；几乎没有哪个能列举出它的例外。下面是完整清单，每项权力都附有限制它的那一条。

- **交易场所注册表、桥接币列表和 V4 钩子白名单**——经人工策划；恶意上架的最坏情况受你的最低值与 Iron-Law 底线 Φ 中较严格者限制；本金它触及不到（§9.6、§14.6）。
- **放弃之前的 Router 控制密钥**——可以重定向费用去向、暂停兑换、重新指向其原生资产入口和 Permit2 入口所调用的 WETH 与 Permit2 合约，并在 48 小时公开延迟后找回误发的代币；不能改动费率、分配或底线（编译期常量，无设置函数），也触及不到本金（无代理、无升级路径、无 `selfdestruct`、静止时不持有任何资产）。
- **放弃之前的 Hub 控制密钥**——可以重新指向 Hub 对 Router、Solver 和 Quoter 的引用，重新指向 V4 管理器，暂停注册表的学习，并授予操作员席位；无法让一笔成交定价错误，因为任何为交易定价的部分都不读取注册表。
- **金库**——在构造时固定，30 / 70 的分配没有设置函数。
- **入口所依赖的标准合约**——Permit2 入口依赖 Uniswap 的 Permit2，原生资产入口依赖该链的 WETH，V4 分支依赖 PoolManager：每一个都只通过其入口或其分支调用，而 Router 以自己实测的余额增量为每个分支定价，因此不诚实的对手方只会让输出崩塌，而你的界限会拒绝这笔兑换。
- **代币与对应关系**——BZPX 满足其六项部署不变量，以及你调用的地址与本文相对应：一旦 §19 的记录公布即可检查，按 §19 规定的程序进行。

你无需信任的：任何人为你的交易定价——路由在执行帧内从公开状态推导，如果是你自带的则在那里重新测量；任何人公平地为它路由——底线在链上根据实测输出重新推导，而费用没有随报价与交付差距增长的项；任何人计算费用——Router 不支付费用就拒绝结算；以及任何人持续为你服务——即使本项目运营的所有服务器今晚消失，合约明天仍会像今天一样报价、路由和结算。

如果你只从本文保留一个习惯，那就是为自己的交易设定最低值。聚合器中的每一道界限最终都回退到这个数字；它是系统中唯一一项其质量不取决于任何人的能力、只取决于你自己的保护。

## §23 相关工作

**路由。** Angeris、Evans、Chitra 和 Boyd 将跨恒定函数做市商的路由表述为一个凸规划，其最优解使各交易场所的边际价格相等；Diamandis、Resnick、Chitra 和 Angeris 为其给出了一种高效的对偶分解算法。本设计在链上刻意停在该最优解之前：拆分分配器一次完成、按深度成比例（§10.4），不需要迭代，也不需要逐场所的曲率模型，并且在迭代求解器意味着 gas 账单和攻击面的地方保持稳健；蜕变通道测量了这一选择的代价——拆分的支付从不少于最佳单一池（MR-R1），而保真度矩阵显示 Solver 在 Base 上的路由与穷举网格相差在 0.13 bps 以内。恒定乘积族精确的边际收益均衡闭式解，对每个交易场所只需两个求和与一个平方根，是后续版本的候选；目标函数在最优点附近是平坦的，这就是稳健规则先发布的原因。链下求解器设计把优化移到服务器上，把合约降格为检查器；§3.1 的依赖预算（Dependency Budget）就是本文对其代价的说明。近期工作把 gas 纳入模型：*Optimal Routing across Constant Function Market Makers with Gas Fees* 表明 gas 会扩大无交易区域，并与碎片化发生非平凡的相互作用；*Routing Frictions and Executable Liquidity in Fragmented Markets* 区分了宣称的流动性与可执行的流动性——本设计在帧内测量而非建模的正是这一区别。

**稳健聚合。** §10.3 的可信中心是一个按深度加权的中位数，其崩溃点为权重的一半。Müller、Moumeni 和 Messaoudi 在 *Cost of Manipulation in AMM-Based Oracles*（FC 2026）中为聚合 AMM 价格的预言机证明了相应的界：等权重时，最便宜的攻击是移动最浅的池子；而按流动性加权时，控制一半权重至少需要总报价深度的一半。Ormer 提出了一种估计中位数的链上预言机来取代 TWAP 均值，*From Means to Medians* 则研究了哪些基准最难被操纵。E25 把同一原则应用于路由：一个池子只在其背后承担风险的资本所及的范围内被信任。

**交易场所。** Uniswap v2 给出了恒定乘积的参考以及 V2 分支默认采用的 30 bps 惯例；Uniswap v3 给出了集中流动性模型、`slot0` 以及 §4.2 闭式公式所遵循的 Q64.96 定点数；Uniswap v4 给出了单例合约（singleton）、闪电记账以及 §5 和 §14.2 所依赖的钩子权限地址编码——据我们所知，本设计是第一个完全在帧内推导、证明、定价、筛查并结算 V4 池子的设计。Egorov 的 StableSwap 定义了 Curve 族的放大不变量，本协议选择移除该族，而不是在一个未经测量的信任假设上支持它（§4.1）；§6 的 Solidly 稳定曲线没有经同行评审的论文，以其已部署的实现作为引用。

**MEV。** Daian 等人命名了排序对手并展示了其规模；Zhou 等人测量了去中心化交易所上的三明治攻击，并将其盈利能力形式化。本文不声称消除了它——排序在合约代码运行之前就已决定——而是测量其界限：§14.3 的三明治曲线，从攻击者的角度出发，包含拒绝边缘以及越过它之后攻击者为负的往返收益。

**验证。** Clarkson 和 Schneider 的超性质（hyperproperties）命名了 §21 再分配发现所属的类别——关于轨迹集合而非单条轨迹的性质——并解释了为何守恒律可以成立而错误的一方却得到支付。Cousot 与 Cousot 的抽象解释是单 tick 闭式公式的框架：对交易场所数学的一种抽象，在某一范围内精确，在范围外单向可靠，而底线就是具体化检查。Chen、Cheung 和 Yiu 提出了蜕变测试，即在不存在独立于公式的预言机（oracle）时 §15.7 的第二位裁判。DeMillo、Lipton 和 Sayward 提出了变异分析，§15.2 的精选守卫依赖其耦合假设。Avizienis 的 N 版本编程是 §15.8 的前身，只不过应用于代码生成而不是独立团队。Kuhn、Kacker 和 Lei 的组合测试为 §15.4 的覆盖数组提供了构造方法与主张：制度因子的每一个 t 路交互都按构造被覆盖，并印出分母。Littlewood 和 Strigini 关于验证超高可靠性的结果，是本文任何地方都不给出正确性概率的原因。

**标准。** EIP-1153 瞬态存储承载单一回调原则的分支上下文、费用账本和重入锁；EIP-170 是 24,576 字节的上限，Router 和 Hub 距它只有几百字节；EIP-1014 是 𝒟 的 CREATE2 算术；EIP-2612 和 Uniswap 的 Permit2 定义了第二个入口基于签名的转账；ERC-7201 为 Hub 的存储划分命名空间；EIP-7702 委托账户与任何合约一样调用相同的入口。

## §24 结论

我们着手以一条纪律构建一个聚合器——测量，而不是相信——并在每一个原本可以凭别人一句话接受某个数字的地方坚持它：路由、价格、底线、费用基数、交易场所集合、池子声称交易的交易对，甚至协议自身的成本模型。

结果是一个小而结构坚实的系统。流动性碎片化原来是语言问题，而不是数学问题：在交易场所的泛滥之下，是一小族不变量；一个把每个不变量都只表达一次的协议——一个调度器、一个推导、一道底线、一个活力场——能够在没有逐场所特例的情况下为整个格局定价，在执行它的交易内部推导路由，并在代币到达你之前对照实测输出重新检查自己的承诺。实测记录是对这一切所得最简短的总结：无漂移报价 64 次中 64 次按预测精确结算，无论在模拟环境还是实时 Base 上；一道底线把 1 % 交易上的三明治攻击限制在约其 2.7 %，超出即拒绝；四条链上预览与交付相差 0–1 个基点；以及一套连同分母一起公开其可能被如何操纵、以及它看不到什么的测量装置。

它的代价同样清楚。gas：在帧内推导路由比结算一个在别处算好的答案更贵——这是一个你可以检查、而不必凭别人一句话接受的保证的价格——而字节–gas 汇率按链告诉你哪个入口让这个价格最小。不可变性：缺陷会被公开并给予赏金，而不是修补——这是一个只需审计一次的合约的价格，而 §21 就是这个价格换来的东西。

重述论点：做选择的就是做交易的。报价与其执行是同一次计算，所以过去由运营者诚信填补的缝隙，如今由算术封闭；一个通过交易来学习流动性、并证明其存储的每个交易对的注册表；一项费用、一道底线和一个入口面，任何人——包括作者——都无法改动，因为它们已编译在内。协议不要求被信任。它要求被验证，并努力让验证变得廉价、公开且永久。

## §25 Staking V4：设计

Staking V4 是当前的代码库；地址将在上线时公布。

本章按源代码的现状描述质押引擎：`Blaze-Phoenix-Staking` 仓库中的 `src/BlazePhoenixStaking.sol`，`main` 分支位于 `cc614f9`（2026-10-14），其中声明 `VERSION = "4.0.0"`（L169）。本章中的每个行号（L*n*）均指该提交下的该文件；本文与源代码不一致之处，以源代码为准。本章不含任何地址、部署日期或收益率：其中每个数字要么是编译进合约的常量，要么由某个常量推导而来，推导过程就印在旁边。

该引擎遵循本文其余部分的同一纪律。它只持有一种代币 BZPX，对这些 BZPX 的每一项权利都是一个账本项，合约在每次状态变更前后重新核对这些项之和（E35）。质押者按自选的天数锁定 BZPX，并获得两股收益流——按计划的排放（E27–E29）和借款人支付的利息（E31–E34）——每股都按随承诺增长的加成加权（E30）。质押者可以以其质押为抵押借入 BZPX（E41）。发生损失时，损失按一个固定顺序处理（E37），合约还以公开视图的形式报告它是否持有其所欠的资产（E36）。

### §25.1 架构与角色

一个合约 `BlazePhoenixStaking`，继承 `AccessControl`、`Pausable` 和 `ReentrancyGuard`（L167）。代币、金库以及排放窗口（`emissionStart`、`emissionEnd`）均为 immutable（L266–269）；构造函数拒绝不含代码的代币地址（L477）。没有预言机（oracle），没有升级路径，也没有参数设置函数：下文的每个常量都已编译进合约。

| 角色 | 持有者 | 可执行 | 行 |
|---|---|---|---|
| `DEFAULT_ADMIN_ROLE` | 部署者，于构造时 | 授予和撤销角色（不存在 `_setRoleAdmin` 调用，因此它管理所有角色） | L485 |
| `ADMIN_ROLE` | 部署者，于构造时 | `fundEmission`（累计注资 ≤ `TOTAL_REWARDS`）；`withdrawReserve`（只能转入不可变的金库，至多 `protocolReserve`，硬性违约时关闭）；`sweepUndistributedEmission`（仅在 `emissionEnd` 之后）；`unpause`；`cancelEmergency`（仅在账本具备偿付能力时） | L486, L516, L533, L563, L580, L618 |
| `GUARDIAN_ROLE` | 构造时无人持有；由角色管理员授予 | `pause`；`declareEmergency`——两者都不移动资金 | L171, L578, L608 |
| 任何人 | — | `liquidate`；`tripBreaker`（除非账本处于硬性违约，否则回滚）；`absorbBadDebt`；`lockStep` | L1066, L597, L639, L1291 |

没有任何角色能够移动质押者的本金，任何角色能把收入转往的唯一目的地是不可变的金库。

| 常量 | 值 | 含义 | 行 |
|---|---|---|---|
| `TOTAL_REWARDS` | 180,000,000e18 | 排放预算，也是累计 `fundEmission` 的上限 | L192 |
| `HALVING_PERIOD` | 2 × 365 days | 一个排放周期的长度 | L193 |
| `EMISSION_PERIODS` | 8 | 计划结束前的周期数（`EMISSION_LENGTH` = 16 年） | L194–195 |
| `INITIAL_REWARD_PER_SEC` | (`TOTAL_REWARDS` / 2) / `HALVING_PERIOD` | 第 0 周期的速率 $R_{0}$ | L196 |
| `MAX_STAKE_PER_WALLET` | 30,000,000e18 | 每个仓位的质押上限 | L198 |
| `MIN_EMISSION_WEIGHT` | 1,000e18 | 总权重低于此值时，两股收益流按比例节流 | L208 |
| `MAX_LTV` | 50 | 借款上限，净质押的 % | L210 |
| `LIQ_THRESHOLD` | 95 | 债务 ≥ 质押的 95 % 时可被清算 | L211 |
| `LIQ_BONUS_BPS` | 500 | 给调用者的清算盈余，以债务的 bps 计 | L212 |
| `RESERVE_FACTOR_BPS` | 300 | 每个利息切片中留存于 `protocolReserve` 的份额 | L213 |
| `MIN_LOCK_DAYS`, `MAX_LOCK_DAYS` | 90, 2,555 | 以天计的锁定界限 | L221–222 |
| `BOOST_BASE`, `BOOST_LINEAR`, `BOOST_QUAD` | 10,000, 750, 250 | 加成多项式，bps | L224–226 |
| `MIN_DEPOSIT_BLOCKS` | 10 | 存入后须经过的区块数，之后才能提取、领取纯收益或更改锁定 | L228 |
| `RATE_R0`, `RATE_RK`, `RATE_UK`, `RATE_S1`, `RATE_S2` | 100, 500, 0.8e18, 500, 72,500 | 带拐点的利率曲线，年化 bps | L231–235 |
| `MAX_PROTOCOL_UTIL_WAD` | 0.75e18 | 新借款所允许的账本利用率上限 | L242 |
| `CONSERVATION_DUST` | 1e10 | 守恒守卫的容差，以 wei 计 | L247 |
| `MAINT_BASE`, `MAINT_DENSITY`, `MAINT_GAP_UNIT`, `MAINT_MAX_SCAN`, `MAINT_MAX_LOCK_ACTIONS` | 1, 50, 15 minutes, 10, 4 | 自主维护预算（E42） | L252–255, L263 |

### §25.2 流程：质押、解除质押、领取、借款

每个用户入口都运行同一条流水线，顺序由 `deposit` 确定：对守恒恒等式做快照；若账本处于硬性违约则拒绝；推进利息指数和排放窗口（`_updateGlobal`，L1428）；按仓位原有的权重结算两股收益流；归属该仓位所欠的利息（`_accrueInterestFor`，L1627）；清除已到期的锁定；执行操作；通过唯一写入者重新计算仓位的权重（`_resync` → `_applyBoost` → `_checkpoint`，L1726–1756）；运行自主维护窗口（E42）；并再次检查守恒恒等式（E35）。各个入口的区别仅在于各自附加的关口。

| 入口 | 暂停 | 紧急状态 | 硬性违约 | 其他条件 |
|---|---|---|---|---|
| `deposit(amount, lockDays)`——质押 | 关闭 | 关闭 | 关闭（L760） | $90 \le$ `lockDays` $\le \min(2{,}555,\ \text{days left to } \mathtt{emissionEnd})$；仓位质押 ≤ `MAX_STAKE_PER_WALLET`；在 `emissionEnd` 之前（L743–760） |
| `lock(lockDays)` | 关闭 | 关闭 | — | 距上次存入已过 `MIN_DEPOSIT_BLOCKS`（L964–971） |
| `withdraw(amount)`——解除质押 | 开放 | 关闭 | 关闭（L902） | 无债务；锁定已到期；距上次存入已过 `MIN_DEPOSIT_BLOCKS`（L890–895） |
| `claimRewards()` | 开放 | 关闭 | 关闭（L932） | 结算排放与纯收益（L930） |
| `claimPureYield()` | 开放 | 关闭 | 关闭（L948） | 无债务；距上次存入已过 `MIN_DEPOSIT_BLOCKS`（L944–948） |
| `borrow(amount)` | 关闭 | 关闭 | 关闭（L826） | E41（L820–840） |
| `repay(amount)` | 开放 | 关闭 | 开放 | —（L858） |
| `liquidate(user)` | 关闭 | 关闭 | 开放 | E39（L1066） |
| `emergencyWithdraw()`——退出 | — | 仅此时 | — | E40（L658） |
| `absorbBadDebt(amount)` | 开放 | 开放 | 开放 | E38（L639） |

**质押。** `deposit` 将 BZPX 转入仓位，并开始或延长其锁定；锁定永远不能超过排放计划的结束时间，而它换来的加成（E30）只在锁定有效期间支付。**解除质押。** 一旦仓位不欠任何东西且锁定已到期，`withdraw` 即返还本金；它在守护者暂停期间仍保持开放，因此暂停只阻止新的风险，而不会困住任何人。在紧急状态下，唯一的出口是 `emergencyWithdraw`，它支付净权益，若合约持有的资产少于欠各仓位的数额则按比例缩减（E40），并没收该仓位未领取的收益流。**领取。** 收获就是这两种领取：`claimRewards` 支付两股收益流，`claimPureYield` 对无债务仓位做同样的事；不存在单独的收获函数。**借款、还款、清算。** 质押者可以在两个上限之内以自己的质押为抵押借入 BZPX（E41）；利息从质押中扣除，而不是加到债务上（E34）；`repay` 在暂停和硬性违约期间都保持开放，因为偿还债务只会让账本更安全。债务达到其质押 95 % 的仓位可由任何人平仓，平仓者获得 E39 的盈余。

![FIG-19 — 质押入口及其唯一的流水线：每个入口附加的关口，然后是守恒快照、违约关口、全局更新、结算、利息归属、锁定到期、操作本身、唯一写入者重同步、自主维护以及守恒检查；紧急出口独立于其外。](https://blazephoenix.xyz/whitepaper/figs/zh/fig-19.png)

### §25.3 奖励记账

**排放。** 令 $T$ = `TOTAL_REWARDS`、$P$ = `HALVING_PERIOD`、$R_{0}$ = `INITIAL_REWARD_PER_SEC`、$s$ = `emissionStart`，对时间 $t$ 令 $\tau = t - s$、$p = \lfloor \tau / P \rfloor$。累计计划排放有一个闭式表达（`_emittedAt`，L1458–1467）：

$$
E(t) \;=\; \begin{cases} 0 & t \le s \\ \left(T - (T \gg p)\right) \;+\; (R_{0} \gg p)\,(\tau - pP) & s < t < s + 8P \\ T - (T \gg 8) & t \ge s + 8P \end{cases}
$$
^e27

*推导。* 在精确算术中，第 $q$ 周期的速率为 $T/(2^{q+1}P)$，因此完整的第 $q$ 周期排放 $T/2^{q+1}$，第 $p$ 周期之前的排放为 $\sum_{q<p} T/2^{q+1} = T(1 - 2^{-p})$。$T = 1.8\times 10^{26}$ 能被 $2^{8}$ 整除，所以对 $p \le 8$ 有 $T \gg p = T/2^{p}$ 精确成立，第一项就是该和，没有任何舍入。速率项向下取整：$R_{0} \gg p = \lfloor\lfloor T/(2P)\rfloor / 2^{p}\rfloor = \lfloor T/(2^{p+1}P)\rfloor$，比精确速率少不到每秒一 wei。因此在一个周期内 $E$ 线性增长并保持在精确曲线之下；在每次周期切换时它跃升 $T/2^{p+1} - (R_{0} \gg p)\,P$，这一跃升非负且小于 $P$ wei，使其回到精确序列。$E$ 单调不减，并在 $T - T/2^{8} = \tfrac{255}{256}\,T$ 处结束：最后的 $T/256$ 从不被纳入计划，它与任何空窗口或未注资窗口留下的部分一起，只能在结束后通过 `sweepUndistributedEmission` 回收到金库（L563）。对八次周期切换的精确整数计算确认，每次跃升都为正且小于 $P$。

![FIG-20 — 计划排放 E27 随时间的变化：速率每两年减半，累计曲线在十六年后于 TOTAL_REWARDS 的 255/256 处结束；这是计划而非实付——没有权重的窗口不排放任何东西。](https://blazephoenix.xyz/whitepaper/figs/zh/fig-20.png)

**窗口。** 在每个入口，令 $W$ = `totalBoostedEffective`、$W_{\min}$ = `MIN_EMISSION_WEIGHT`、$t_{\ell}$ = `lastRewardTime`、$t' = \min(t, \mathtt{emissionEnd})$，已流逝的窗口被支付进按权重计的累加器 $A$ = `accRewardPerShare`（`_updateGlobal`，L1428–1448）：

$$
r \;=\; \min\!\left( \left\lfloor \frac{\left(E(t') - E(t_{\ell})\right)\cdot \min(W, W_{\min})}{W_{\min}} \right\rfloor,\ \mathtt{rewardReserve} \right), \qquad A \;\leftarrow\; A + \left\lfloor \frac{r \cdot 10^{18}}{W} \right\rfloor
$$
^e28

`rewardReserve` 减少 $r$，`totalRewardDistributed` 增加 $r$。当 $W = 0$ 时时钟前进而什么也不被捕获，因此没有人继承积压；低于 $W_{\min}$ 时窗口按比例节流，因此一个尘埃级仓位无法独占整个计划；并且由于每个窗口以储备为上限，`fundEmission` 会在新资金到账之前先结算时钟（L523），因此一次补充注资永远不会追溯支付某个窗口。

**结算。** 排放权重为 $w_{u}$、检查点为 $c_{u}$（`rewardDebt`）的仓位应得（`_settlePendingRewards`，L1487–1497；纯收益的对应函数 L1499–1517 使用 $w^{\mathrm{p}}_{u}$、$A^{\mathrm{p}}$ 和 `pureYieldDebt`）：

$$
\mathrm{due}_{u} \;=\; \left(\left\lfloor \frac{w_{u}\,A}{10^{18}} \right\rfloor - c_{u}\right)^{+}, \qquad c_{u} \;\leftarrow\; \left\lfloor \frac{w_{u}\,A}{10^{18}} \right\rfloor
$$
^e29

并且每次权重变化后，唯一写入者都会重新设置检查点 $c_{u} = \lfloor w_{u}A/10^{18}\rfloor$（`_checkpoint`，L1736），因此仓位只在其权重就位后才结束的窗口上获得收益。

**加成。** 权重等于仓位的质押乘以一个加成，该加成是仓位*当前*所支付锁定的多项式（`boostByDays`，L496–505；`_effectiveLockDays`，L1687；`_computeBoost`，L1695–1700）。其中 $\ell$ 为以天计的锁定——一旦解锁时间已过即为零，无论仓位是否已被规范化——上限为 2,555：

$$
b(\ell) \;=\; 10^{4} + \left\lfloor \frac{750\,\ell}{365} \right\rfloor + \left\lfloor \frac{250\,\ell^{2}}{365^{2}} \right\rfloor \ \text{bps}, \qquad w_{u} = \left\lfloor \frac{(s_{u} - d_{u})^{+}\, b}{10^{4}} \right\rfloor, \qquad w^{\mathrm{p}}_{u} = \begin{cases} \lfloor s_{u}\, b / 10^{4} \rfloor & d_{u} = 0 \\ 0 & d_{u} > 0 \end{cases}
$$
^e30

其中 $s_{u}$ 为仓位的质押，$d_{u}$ 为其债务。精确值：$b(90) = 10{,}199$、$b(365) = 11{,}000$、$b(730) = 12{,}500$、$b(1{,}825) = 20{,}000$、$b(2{,}555) = 27{,}500$ bps。排放权重基于净质押；纯收益权重只存在于无债务仓位——借款人不会从自己支付的利息中获益。

### §25.4 利息：曲线与指数

**曲线。** 利用率为 $U = \min(\lfloor D \cdot 10^{18} / S \rfloor, 10^{18})$，其中 $D$ = `totalDebt`、$S$ = `totalStaked`（若 $S = 0 < D$ 则 $U = 10^{18}$；若两者均为零则取基础利率），以 bps 计的年化利率在 80 % 处有拐点（`_interestRate`，L1768–1782）：

$$
r(U) \;=\; \begin{cases} 100 + \left\lfloor 500\,U / 10^{18} \right\rfloor & U \le 0.8 \cdot 10^{18} \\ 500 + \left\lfloor 72{,}500\,(U - 0.8\cdot 10^{18}) / 10^{18} \right\rfloor & U > 0.8 \cdot 10^{18} \end{cases}
$$
^e31

两个分支在拐点处相接——$100 + 0.8 \times 500 = 500$——曲线在满利用率时达到 $500 + 0.2 \times 72{,}500 = 15{,}000$ bps。借款不得使账本超过 75 %（E41），因此任何借款本身都不会进入陡峭分支。

**指数。** 每个已流逝的切片 $\Delta t$ 都按其间有效的利率打上标记，且在对 $D$ 或 $S$ 的任何写入之前进行（`_interestSlice`，L1589–1619；`_updateInterestIndex`，L1539–1583），其中 $Y$ = 365 days：

$$
\delta \;=\; \left\lfloor \frac{\lfloor 10^{18}\, r(U) / 10^{4} \rfloor \cdot \Delta t}{Y} \right\rfloor, \qquad \sigma \;=\; \left\lfloor \frac{D\,\delta}{10^{18}} \right\rfloor, \qquad I \leftarrow I + \delta, \quad S \leftarrow S - \sigma
$$
^e32

若 $\sigma$ 将超过 $S$，则指数增量重新推导为 $\delta = \lfloor S \cdot 10^{18}/D \rfloor$，并据此重新计算 $\sigma$，因此各仓位的扣费之和永远不会超过全局扣减。该算术饱和到零而不是回滚，因此在其之下运行的入口不会被冻结；在紧急状态下，时钟滑动而不扣费（L1547）。同一个函数既为执行也为每次报价计算切片，因此两者不可能出现不同的舍入。

**拆分。** 切片离开质押，并在同一步中被分配（L1560–1580；`_dampPure`，L1623–1625），其中 $W_{\mathrm{p}}$ = `totalBoostedPure`、$A^{\mathrm{p}}$ = `accPureYieldPerShare`：

$$
\kappa_{r} = \left\lfloor \frac{300\,\sigma}{10^{4}} \right\rfloor, \quad \pi = \sigma - \kappa_{r}, \quad \eta = \left\lfloor \frac{\pi \cdot \min(W_{\mathrm{p}}, W_{\min})}{W_{\min}} \right\rfloor, \quad A^{\mathrm{p}} \leftarrow A^{\mathrm{p}} + \left\lfloor \frac{\eta \cdot 10^{18}}{W_{\mathrm{p}}} \right\rfloor, \quad \mathtt{protocolReserve} \mathrel{+}= \kappa_{r} + (\pi - \eta)
$$
^e33

因此 $\sigma = \kappa_{r} + \eta + (\pi - \eta)$ 精确成立；没有纯收益权重时，$\pi$ 全部进入储备。节流方式与排放相同（E28），使用同一个常量。

**归属。** 全局一侧在利息计提时已经结算；仓位自身的份额在其下一次被触及时归属（`_accrueInterestFor`，L1627–1671），其中 $I_{u}$ 为该仓位对指数的检查点：

$$
i_{u} \;=\; \left\lfloor \frac{d_{u}\,(I - I_{u})}{10^{18}} \right\rfloor; \qquad i_{u} > s_{u} \;\Rightarrow\; \lambda = i_{u} - s_{u} \ \text{enters E37},\ S \mathrel{+}= \lambda,\ i_{u} \leftarrow s_{u}; \qquad s_{u} \leftarrow s_{u} - i_{u}, \quad I_{u} \leftarrow I
$$
^e34

利息从质押中支付；债务本身不增长。无债务仓位只重新设置检查点，因此它永远不会继承其不欠款期间的指数增长。仓位无力支付的利息仍已由 E33 分配出去；将其加回 $S$ 可保持 $S = \sum_{u} s_{u}$，而该损失在得知的那一刻由 E37 入账。

### §25.5 储备、偿付能力与损失瀑布

**守恒。** 令 $B$ 为合约的 BZPX 余额，$D$ = `totalDebt`、$\mathit{BD}$ = `totalBadDebt`、$S$ = `totalStaked`、$\mathit{RR}$ = `rewardReserve`、$\mathit{PR}$ = `protocolReserve`，$\Pi$ = `totalRewardDistributed − totalRewardsPaid`（已分配、尚未支付）。每个带有 `conserves` 修饰符的函数都在函数体执行前对两侧做快照，并在执行后回滚，除非满足下式（L419–438；`_conservationSnapshot`、`_conservationCheck`，L449–457）：

$$
\left|\, \Delta(B + D + \mathit{BD}) \;-\; \Delta(S + \mathit{RR} + \mathit{PR} + \Pi) \,\right| \;\le\; \varepsilon, \qquad \varepsilon = \mathtt{CONSERVATION\_DUST} = 10^{10}\ \text{wei}
$$
^e35

每一项都是单个非负状态变量，求和时不设下限，因此该恒等式在每种状态下都是线性的——包括终端困境，此时恢复工具（`repay`、`liquidate`、`absorbBadDebt`）必须继续工作——并且只比较一次调用前后的变化，因此历史无法累积成误报。

**偿付能力。** 合约所欠的数额，以及它是否持有该数额的公开检验（`_owed`，L1794–1798；`_hardBreach`，L1808–1810；`isSolvent`，L1824）：

$$
\mathrm{owed} \;=\; (S + \mathit{RR} + \mathit{PR} - D)^{+} \;+\; \Pi, \qquad \mathrm{hardBreach} \iff B + \varepsilon < \mathrm{owed}, \qquad \mathtt{isSolvent}() = \neg\,\mathrm{hardBreach}
$$
^e36

*与坏账关系的推导。* 当 $S + \mathit{RR} + \mathit{PR} \ge D$ 时，E35 在每次受守卫的调用前后给出 $\Delta(B - \mathrm{owed} + \mathit{BD}) = 0$（误差在 $\varepsilon$ 以内），因此 $B - \mathrm{owed} = c - \mathit{BD}$，其中 $c$ 为账本之外持有的余额。所以，已记录的坏账恰恰是把账本推向硬性违约的那一项，一旦 $\mathit{BD} > c + \varepsilon$，账本即显示为无偿付能力。在硬性违约下，那些会按面值付款或向短缺资金池注入新资金的入口都会回滚——`deposit`、`borrow`、`withdraw`、`claimRewards`、`claimPureYield` 及其内部的纯收益结算、`withdrawReserve`、`cancelEmergency`（L760, L826, L902, L932, L948, L1510, L539, L620）——而 `repay`、`liquidate` 和 `absorbBadDebt` 保持开放，并且任何人都可以调用 `tripBreaker` 使合约进入紧急状态（L597）。

**瀑布。** 损失 $\lambda$ 只在三处产生：债务超过质押的清算（L1101–1106, L1128）、资不抵债的紧急退出（L704–709），以及仓位无力支付的利息（L1657–1663）。三者都采用同一顺序：

$$
\kappa \;=\; \min(\lambda,\ \mathit{PR}), \qquad \mathit{PR} \leftarrow \mathit{PR} - \kappa, \qquad \mathit{BD} \leftarrow \mathit{BD} + (\lambda - \kappa)
$$
^e37

储备——由每个利息切片的储备系数（E33）和自我清算奖金积累而成——首先吸收损失；只有未覆盖的剩余部分才成为已记录的坏账。资本重组是一个公开入口，它先动用储备，再至多动用调用者提供的数额，且永远不超过仍未覆盖的部分（`absorbBadDebt`，L639–649），其中 $a$ 为调用者提供的数额：

$$
\rho \;=\; \min(\mathit{BD},\ \mathit{PR}), \qquad \gamma \;=\; \min(a,\ \mathit{BD} - \rho), \qquad \mathit{PR} \leftarrow \mathit{PR} - \rho, \qquad \mathit{BD} \leftarrow \mathit{BD} - \rho - \gamma, \qquad B \leftarrow B + \gamma
$$
^e38

当 $\rho + \gamma = 0$ 时它回滚，它不向外转出任何资产，也不向调用者支付任何东西；E35 按构造成立（$\Delta \mathrm{LHS} = \gamma - \rho - \gamma = -\rho = \Delta \mathrm{RHS}$）。一旦 $\mathit{BD}$ 回到尘埃容差以内，`isSolvent()` 即读为 true，管理员可以取消紧急状态。

**清算。** 仓位可被清算当且仅当 $d_{u} > 0$ 且（$s_{u} = 0$ 或 $100\,d_{u} \ge 95\,s_{u}$）（`_isLiquidatable`，L1133–1137）。平仓（`_executeLiquidation`，L1079–1131）：

$$
\mathrm{seized} \;=\; \min\!\left(d_{u} + \left\lfloor \frac{500\,d_{u}}{10^{4}} \right\rfloor,\ s_{u}\right), \qquad \mathrm{bonus} \;=\; (\mathrm{seized} - d_{u})^{+}, \qquad \lambda \;=\; (d_{u} - s_{u})^{+} \ \text{to E37}
$$
^e39

奖金归调用者，但借款人平掉自己的仓位时除外，此时奖金留在 `protocolReserve` 中。仓位已赚取的收益流在平仓前支付，剩余的质押保留为一个无债务仓位，并保持其锁定。

**紧急退出。** 令 $\mathrm{pot} = B$，$E_{+}$ = `totalPositiveEquity` $= \sum_{u} \max(s_{u} - d_{u}, 0)$（按跟踪值），退出支付（`emergencyWithdraw`，L658–725；缩放部分，L689–696）：

$$
x_{0} \;=\; (s_{u} - d_{u})^{+}, \qquad E' \;=\; E_{+} - e_{u} + x_{0}, \qquad x \;=\; \min\!\left( \begin{cases} \lfloor x_{0}\,\mathrm{pot} / E' \rfloor & \mathrm{pot} < E' \\ x_{0} & \text{otherwise} \end{cases},\ \mathrm{pot} \right)
$$
^e40

其中 $e_{u}$ 为退出者的跟踪项，在计提后被替换为其精确权益。在具备偿付能力的账本上，缩放永远不会生效，净权益全额支付；在短缺的账本上，每次退出都拿走其债权的相同比例，资不抵债的退出则通过 E37 记录其缺口（L704–709）。

![FIG-21 — 损失瀑布 E37–E38：protocolReserve 首先吸收，其余部分记为 totalBadDebt 并由 isSolvent() 读取，absorbBadDebt 先从储备、再从调用者处进行资本重组，绝不超过未覆盖的部分；比例仅为示意，不含代币数额。](https://blazephoenix.xyz/whitepaper/figs/zh/fig-21.png)

**借款上限。** 数额为 $a$ 的借款必须同时满足两者（`borrow`，L834–840；`_ltvCap`，L1908–1909）：

$$
d_{u} + a \;\le\; \left\lfloor \frac{50\,(s_{u} - d_{u})^{+}}{100} \right\rfloor, \qquad \left\lfloor \frac{(D + a)\cdot 10^{18}}{S} \right\rfloor \;\le\; 0.75 \cdot 10^{18}
$$
^e41

第一个针对仓位的净质押，第二个针对整个账本，使其保持在 E31 的 80 % 拐点之下。

**维护。** 除非合约处于暂停或紧急状态，每笔用户交易还会扫描借款人注册表的一个窗口（清算资不抵债者）和锁定注册表的一个窗口（规范化已到期的锁定），每个窗口的大小为（`_windowBudget`，L1148–1157；`_autoMaintain`，L1170–1178）：

$$
c(n) \;=\; \min\!\left(1 + \left\lfloor \frac{n}{50} \right\rfloor + \left\lfloor \frac{t - t_{m}}{15\ \mathrm{min}} \right\rfloor,\ 10,\ n\right)
$$
^e42

其中 $n$ 为注册表大小，$t_{m}$ 为上一次扫描的时间；每笔交易至多执行四次锁定规范化（L263）。该调度是链上状态的纯函数——没有 keeper，没有治理——其 gas 在任何情况下都有界。

**不变量。** 本设计新增九个不变量 INV-23 至 INV-31（附录 B）：守恒恒等式、排放上限、损失顺序、违约时关闭的入口、资本重组的界限、权重的唯一写入者、借款上限、有界的紧急退出，以及存入后的等待规则。

### §25.6 V4 中的加固

在已部署于 Base 的设计之后，三项已合并的变更塑造了 V4 源代码；此处按每项变更所产生的设计层面加以描述。

- **#22（`b44e238`，2026-10-11）。** 利息由执行与每次报价共用的同一个函数按切片打上标记（E32），因此预览和交易计算出相同的费用，采用该切片期间有效的利率。纯收益通道采用与排放相同的权重下限节流（E33），因此残余的分母无法捕获这股流量。借款人平掉自己的仓位时不获得清算奖金。新增了只读风险视图（`healthFactor`、`daysToLiquidation`、`maxBorrowOf`）。
- **#26（`7fc0c2a`，2026-10-13）。** 三个损失来源共用一个损失顺序：先储备，再记为坏账（E37）；一个公开的资本重组入口（E38）；在硬性违约下关闭会移动价值的入口（E36）；构造函数拒绝不含代码的代币地址；守恒检查改为以两个内部辅助函数形式只生成一次，而不是在每个受守卫位置内联，恒等式本身不变；以及一套保障性测试套件。
- **#25（`cc614f9`，2026-10-14）。** 仅涉及文档：在指南和测试文件头中加入简短的摘要行。合约源代码没有任何改动。

### §25.7 测试证据

在 `origin/main` 的 `cc614f9` 上，基于源代码树而非运行结果统计：37 个 `*.t.sol` 文件（`git ls-tree -r --name-only origin/main | grep -c '\.t\.sol$'`），其中声明了 256 个 `test*` 函数和 14 个 `invariant*` 函数（`git grep -E '^\s*function (test|invariant)' origin/main -- '*.t.sol'`，按前缀拆分）。仓库的 README（第 84 行）说明，除此之外还有一个包含九个套件的 Node 测试框架。这些是对已声明内容的计数；本文不报告质押测试套件的通过率。

---

## 修订历史

### 版本 2.3.0（2026-10-14）

2.3.0——新增 Staking V4 设计章（§25），含方程 E27–E42、不变量 INV-23–INV-31 与图 FIG-19–FIG-21；它取代下文“质押引擎不再在本文中描述”的说法。除此之外，只有版本标签、编号范围、附录引言和 DOI 行有所改动；其余为 2.3 的文本。

### 版本 2.3（2026-09-24）

版本 2.3 延续 2.2 系列；曾短暂用于本文草稿的 3.0 编号已撤回，正如 2026-09-01 的 3.0 编号此前已被撤回。相对 2.2 的变化：十八项创新被命名、编号为 I-1 至 I-18，并连同其数学置于文首，附有实测记录的记分板；每个数字都针对 `main` 的 `8916545` 重新测量；质押引擎不再在此描述（由其自身的规范承载）；代币一节记录了单一的 Airdrop & Bounties 池，共 130,000,000 BZPX；下文 2.2 的勘误已并入它们所修正的正文。

### 2.2 勘误（2026-09-07）

在对照 `main 8949a9d` 对 2026-09-06 的文本进行一次挑剔审读后施行；版本号仍为 2.2。每一条都写明正文原来的说法与检出代码的实际情况。

1. §4.2——边界钳位 `sqrtBoundary` 在 Core 中已定义，但尚未接入排序或帧内承诺；正文曾说它已在承诺一侧应用。未决事项：接入它（`Router._v4LegQuote`、Core 排序分支），并配一个先红后绿的测试：当 V4 分支离开其区间时，交付低于净报价且超出 E21 缓冲。
2. §10.4——容量钳位不包括 V4 分支（Solver 对类型 4 和 8 跳过余额读取）；正文曾说每个集中流动性分支都被钳位。未决事项：为单例合约（singleton）找一个物理界限。
3. §5.4——静态费率的 V4 key 忽略了管理器的协议费（在今天服务的每条链上都为零）；正文曾称该 key 的费率是明确无歧义的。
4. §9.3——驱逐裕度最低可降至约 25 %（在位者 51，新来者 64），而不是 3 %；早先的数字违反 E13，且抄自一段源码注释。
5. §15 与摘要——43 个 `invariant_*` 函数（所印命令返回 43），217 个 `.t.sol` 文件。
6. §14.1——`HubE(6)` 不存在；工厂穷尽是 `HubE(4)`，槽位穷尽是 `_canInsert`。
7. §14.2——撤回“任何一层即已足够”：这些层约束的是 delta 的改动；§5.4 的费率覆盖残差由底线约束。
8. §11.4、INV-21——路由形状规则是在整条路由上的规范顺序（`sawHooked`），而不是“带钩子的只能在最后一跳”。
9. §11.3、E24——聚合跳底线的松弛量要除以 BPS：为平均证明分支的 20 %。
10. §17.3 与附录 C——`FactoryCensus` 测试框架位于私有部署树中；该表为报告值，无法从本检出代码复现。
11. §17.5——gas 参照对象已具名（KyberSwap `MetaAggregationRouterV2`，Base 分叉，2026-08-22，Paraswap 为第二个比较对象），且每笔交易的比率（2.7×）与每个分支的比率并列印出；测试框架与采集的 calldata 为私有，因此这些数字为报告值，无法从本检出代码复现。
12. §17.2——撤回“该链上首个经 V4 路由的聚合”；“精确”替换为实测区间（0–1 bps）。
13. INV-8、INV-10、INV-15、INV-20、INV-22——强制执行的引用已更正为承载它们的测试与错误码；INV-22 列出四个已部署合约。
14. §1——对聚合器的调研限定于所列的七个，以 2026-09-07 的记载为准。
15. 参考文献 16 与 20——EIP-1153 的作者是 A. Akhunov 与 M. Salem；EIP-7702 的作者是 V. Buterin、S. Wilson、A. Dietrichs 与 M. Garnett。
16. §2.3、§15.11、§21——仪器校准与缺陷模式的计数替换为校准规则本身。
- §14.2，第 2 层（2026-09-07，钩子准入）：允许列表管理自动入口，codehash 固定则在每个入口上暂停代码已变动的已列入钩子。地址位不携带兑换权限的钩子永远不会在兑换中运行，既不需要列表也不需要固定。在兑换中运行但无人列入的钩子，会作为调用者签名的选择在显式入口上被接受，并与所有交易场所一样受帧内承诺、证明闸门和 `userMinOut` 约束；它永远不会由自动入口提出。注册一个带钩子的池即准入并固定其钩子，因此带钩子的池只需运营者一步操作。三层依然成立；“默认关闭”描述的是自动入口。

### 2.2 勘误（2026-09-24）

在第九轮漏洞赏金之后施行；版本号仍为 2.2。

1. §4.2，以及 2026-09-07 勘误第 1 条——已关闭。V4 池通过遍历其自身的订单簿来报价：它的价格、流动性、tick 位图与各 tick，经 `extsload` 读取，使用 PoolManager 自身的步进算术，排序与承诺皆然（`Core.v4WalkOut`）。边界钳位 `sqrtBoundary` 已退役。“调度器不复制跨 tick 算术”这一说法现在只对 V3 族成立。
2. §10.4，以及 2026-09-07 勘误第 2 条——就其所服务的目的而言已关闭：遍历只计入订单簿在其跨越的 tick 中持有的流动性，因此 V4 分支受其自身池所持有的量约束（`test_AOneTickRangeWithNothingBeyondPaysWhatItHolds`）。
3. 2026-09-07 勘误第 3 条——已关闭：静态费率 key 在兑换方向上将管理器的协议费与 key 的 LP 费复合（`Core.effV4Fee`；`test_StaticKey_ProtocolFee_ReachesThePromise`）。
4. §4——报价路径对池的每一次读取都有 gas 上限，并复制固定数量的字；原先属于高层调用的两处（Solidly 交易对的 `getAmountOut`，以及先 `factory()` 再 `getFee`）改经 `Core._askWord` 询问（`test/APoolsAnswerIsBoundedByTheReader.t.sol`）。

## 附录 A · 基本方程

本文中的每一项定量主张都可归结为下列方程之一。每个方程只在所列合约中实现一次，其他各处均从那里导入。E1–E22 的编号沿用上一版，保持不变；E23–E26 为新增，附于其后。E27–E42（2.3.0）属于质押引擎，定义于质押仓库 `cc614f9` 处的 `src/BlazePhoenixStaking.sol`（§25）；第四列中的“Staking”指该合约，并附其行号。

| # | 名称 | 方程 | 定义位置 | § |
|---|---|---|---|---|
| E1 | 元方程 | $R^{\star} = \arg\max_{R}\ \mathrm{net}(R)\cdot\prod_{\ell}\hat{\Psi}(p_{\ell})\cdot\mathbf{1}[\mathrm{net}(R)\ge\Phi(R)]\cdot\Xi(R)$ | Solver 流水线 | §3 |
| E2 | 恒定乘积输出 | $y = \lfloor x(\mathrm{BPS}-f)\,r_{\mathrm{out}} / (r_{\mathrm{in}}\,\mathrm{BPS} + x(\mathrm{BPS}-f)) \rfloor$ | Core `outV2` | §4.2 |
| E3 | 集中流动性输出（tick 内） | $\sqrt{P}' = L\sqrt{P}/(L + x_{f}\sqrt{P}/Q_{96})$，$y = L(\sqrt{P}-\sqrt{P}')/Q_{96}$；另一方向为对偶形式 | Core `outV3` | §4.2 |
| E4 | V4 存储基槽 | $\mathrm{slot} = \mathrm{keccak256}(\mathrm{abi.encode}(\mathrm{poolId}, 6))$；$\sqrt{P}$ 位于第 0 字的位 [0,160)，LP 费位于 [208,232)；$L$ 位于第 3 字 | Core `v4SqrtAndLiq` | §5 |
| E5 | Solidly 稳定不变量 | $k(x,y) = x^{3}y + xy^{3}$ | Core `_solK` | §6 |
| E6 | Solidly 牛顿步 | 初值 $y_{0} = Y$；上行步 $\max(1, \lfloor (K-k)/f' \rfloor)$；下行步 $\max(1, \lfloor (k-K)/f' \rfloor)$，若会越过零则改为 $\lfloor y/2 \rfloor$；在 $\lvert y_{n+1}-y_{n}\rvert \le 1$ 时退出，并朝不利于接单方的方向调整一个单位；上限 64 → 初值 → 报价 0 | Core `_solY` | §6 |
| E7 | 小数位归一化 | $X = r_{\mathrm{in}}10^{18-d_{\mathrm{in}}}$，$Y = r_{\mathrm{out}}10^{18-d_{\mathrm{out}}}$，求解后再还原比例 | Core `_solidlyStable` | §6 |
| E8 | CREATE2 推导 | $\mathrm{pool} = \mathrm{addr}_{20}(\mathrm{keccak256}(\mathtt{0xff} \Vert \mathrm{origin} \Vert \mathrm{salt} \Vert \mathrm{initCodeHash}))$ | Core `create2Address`、`deriveAddress` | §7 |
| E9 | 单槽（Monoslot）打包 | $s = a \,\vert\, f\!\ll\!8 \,\vert\, k\!\ll\!32 \,\vert\, r\!\ll\!40 \,\vert\, (c\wedge\mathtt{0xFFF})\!\ll\!48 \,\vert\, b\!\ll\!60 \,\vert\, \dots \,\vert\, B_{\mathrm{last}}\!\ll\!224$ | Core `encodeSlot` | §8 |
| E10 | 活力场 | $\Psi = V \cdot 2^{b} \cdot (1 + 0.25\,\mathbf{1}_{\mathrm{bridge}}) \cdot (1 + 0.05\,\mathbf{1}_{\mathrm{conc}})$ | Core `psi` | §9.2 |
| E11 | 活跃度衰减 | $V = \mathrm{swapCount} \gg \lfloor (t - t_{\mathrm{last}})/24{,}576 \rfloor$；移位超过 31 时为 0 | Core `_decayedSwapCount` | §9.2 |
| E12 | 深度档位 | $b = \min(15, \lfloor \log_{10}(d/10^{15}) \rfloor)$ | Core `depthBucket` | §9.2 |
| E13 | 驱逐门槛 | $2^{b(d_{\mathrm{new}})} > \Psi_{\mathrm{worst}} + \lfloor \Psi_{\mathrm{worst}}/4 \rfloor$ | Hub `_canInsert` | §9.3 |
| E14 | 拆分闸门 | 当且仅当 $\mathrm{out}_{\mathrm{split}} \ge \mathrm{out}_{\mathrm{single}}\cdot(1 + 25/10^{6})$ 时保留拆分，$\mathrm{out}_{\mathrm{single}}$ 取最深候选与最佳汇率候选在全额下的较优者 | Solver `_buildHop` | §10.4 |
| E15 | Iron-Law 底线 | $\mathtt{floorBps} = \max(9{,}600 - \mathtt{legShv} - \min(\delta, 10^{4}) - \sigma_{\ln}/10^{14},\ 8{,}000)$ | Core `ironFloorBpsShv` | §11.5 |
| E16 | 有效最小值 | $\mathtt{effMin} = \max(\mathtt{userMinOut},\ \mathtt{route.singleOutFloor},\ \lceil \mathtt{finalHopQuote}\cdot\mathtt{floorBps}/10^{4}\rceil)$；检测到转账收费（fee-on-transfer）时，舍去第二项，第三项按实测净比率重新缩放 | Router `_execute` | §11.5 |
| E17 | 协议费 | $\mathrm{fee} = \lceil 28 \cdot \mathrm{base} / 10^{4} \rceil$，base 为收费跳的实测输入（锚定制度）、毛输出（直接进入桥接币的路由），或每一跳的实测输入（穷尽制度）；$t_{1} = \lfloor 3{,}000\cdot\mathrm{fee}/10^{4} \rfloor$，$t_{2} = \mathrm{fee} - t_{1}$ | Router `_chargeHopFee`、`_payFee` | §13 |
| E18 | 钩子闸门 | $(\mathrm{uint160}(\mathrm{hook}) \,\&\, \mathtt{0x3FFF}) \,\&\, ((1\ll 3)\mid(1\ll 2)) \ne 0 \Rightarrow$ 拒绝该分支，不发起调用 | Core `hookAltersDeltas`；Router | §14.2 |
| E19 | 动态费率闸门 | 若为静态，则 $f_{\mathrm{eff}} = f_{\mathrm{key}}$；若哨兵值伴随非零协议费，则不可报价；否则取来自 `slot0` / `globalState` / 池的 `fee()` 的实时 LP 费 | Core `effV4Fee`、`quoteV3Fee` | §5.4 |
| E20 | V2 费率上限 | 若 $0 < f_{\mathrm{decl}} \le 100$ bps，则 $f_{\mathrm{eff}} = f_{\mathrm{decl}}$，否则为 30 | Core `effV2Fee`；Solidly 声明的回退费率适用同一规则 | §4.2 |
| E21 | 预览安全缓冲 | $s = \min(\max(0, n-2) + 5a,\ 10)$ bps | Quoter `_pack` | §12.1 |
| E22 | 载体选择 | 当且仅当 $p_{\mathrm{byte}} < \rho^{*}$ 时在 calldata 中携带路由；按路由形状实测 $\rho^{*}$ 为 66.9–105.5 gas/字节 | `test/EquationBench.t.sol` | §17.6 |
| E23 | 由集中度导致的分支削减 | $\mathtt{legShv} = \sum_{\mathrm{hops}} \lfloor 200\,((\sum a)^{2} - \sum a^{2})/\sum a^{2} \rfloor$ | Core `legShaveBps` | §11.5 |
| E24 | 聚合跳底线 | $\sum \mathrm{got} + \lfloor (\mathrm{BPS} - 8{,}000)\cdot \lfloor \sum \mathrm{attested}/n \rfloor / \mathrm{BPS} \rfloor \ge \sum \mathrm{attested}$ | Router `_execute` | §11.3 |
| E25 | 可信中心 | 深度加权中位数：将 $(r_{i}, d_{i})$ 按 $r_{i}$ 排序，返回第一个满足 $\sum_{j \le i} d_{j} \ge \lceil \sum d / 2 \rceil$ 的 $r_{i}$；可信带为 $[0.95, 1.05] \times$ 中心 | Solver `_depthWeightedMedian` | §10.3 |
| E26 | 费用制度判定 | $\mathrm{feeHop} = \min\{h : \mathrm{isBridge}(\mathrm{hops}[h].\mathrm{tokenIn})\}$；当且仅当 $\neg\mathrm{feeOnOut} \wedge (\mathrm{feeHop} = \infty \vee h = \mathrm{feeHop})$ 时在 $h$ 收费；$\mathrm{feeOnOut} \iff$ 仅一跳且 $\mathrm{isBridge}(\mathrm{tokenOut})$ | Router `_execute` | §13.1 |
| E27 | 排放闭式解 | $E(t) = (T - (T \gg p)) + (R_{0} \gg p)(t - s - pP)$，$p = \lfloor (t - s)/P \rfloor$；在 $s$ 之前为 $0$；自 $s + 8P$ 起为 $T - (T \gg 8)$ | Staking `_emittedAt`（L1458–1467） | §25.3 |
| E28 | 排放窗口 | $r = \min(\lfloor (E(t') - E(t_{\ell}))\min(W, W_{\min})/W_{\min} \rfloor,\ \mathit{RR})$；$A \mathrel{+}= \lfloor r \cdot 10^{18}/W \rfloor$ | Staking `_updateGlobal`（L1428–1448） | §25.3 |
| E29 | 结算 | $\mathrm{due}_{u} = (\lfloor w_{u}A/10^{18} \rfloor - c_{u})^{+}$，随后 $c_{u} \leftarrow \lfloor w_{u}A/10^{18} \rfloor$ | Staking `_settlePendingRewards`、`_settlePendingPureYield`（L1487–1517） | §25.3 |
| E30 | 锁定加成与权重 | $b(\ell) = 10^{4} + \lfloor 750\ell/365 \rfloor + \lfloor 250\ell^{2}/365^{2} \rfloor$ bps，$\ell$ 为有效中的锁定期；$w_{u} = \lfloor (s_{u} - d_{u})^{+} b/10^{4} \rfloor$；当且仅当 $d_{u} = 0$ 时 $w^{\mathrm{p}}_{u} = \lfloor s_{u} b/10^{4} \rfloor$ | Staking `boostByDays`、`_computeBoost`（L496–505、L1695–1700） | §25.3 |
| E31 | 利率曲线 | 当 $U \le 0.8 \cdot 10^{18}$ 时 $r = 100 + \lfloor 500U/10^{18} \rfloor$，否则为 $500 + \lfloor 72{,}500(U - 0.8 \cdot 10^{18})/10^{18} \rfloor$，单位为每年 bps | Staking `_interestRate`（L1768–1782） | §25.4 |
| E32 | 利息指数与切片 | $\delta = \lfloor \lfloor 10^{18} r/10^{4} \rfloor \Delta t / Y \rfloor$，$\sigma = \lfloor D\delta/10^{18} \rfloor$；若 $\sigma > S$，则 $\delta = \lfloor S \cdot 10^{18}/D \rfloor$ 并重新计算 $\sigma$ | Staking `_interestSlice`、`_updateInterestIndex`（L1539–1619） | §25.4 |
| E33 | 切片分配 | $\kappa_{r} = \lfloor 300\sigma/10^{4} \rfloor$ 归储备；$\eta = \lfloor (\sigma - \kappa_{r})\min(W_{\mathrm{p}}, W_{\min})/W_{\min} \rfloor$ 归纯质押者；其余归储备 | Staking `_updateInterestIndex`、`_dampPure`（L1560–1580、L1623–1625） | §25.4 |
| E34 | 利息归属 | $i_{u} = \lfloor d_{u}(I - I_{u})/10^{18} \rfloor$，从 $s_{u}$ 扣除；超出 $s_{u}$ 的部分作为损失进入 E37 | Staking `_accrueInterestFor`（L1627–1671） | §25.4 |
| E35 | 守恒守卫 | $\lvert \Delta(B + D + \mathit{BD}) - \Delta(S + \mathit{RR} + \mathit{PR} + \Pi) \rvert \le 10^{10}$ | Staking `conserves`（L419–457） | §25.5 |
| E36 | 应付额与偿付能力 | $\mathrm{owed} = (S + \mathit{RR} + \mathit{PR} - D)^{+} + \Pi$；当且仅当 $B + 10^{10} < \mathrm{owed}$ 时为硬性违约 | Staking `_owed`、`_hardBreach`、`isSolvent`（L1794–1824） | §25.5 |
| E37 | 损失瀑布 | $\kappa = \min(\lambda, \mathit{PR})$；$\mathit{PR} \mathrel{-}= \kappa$；$\mathit{BD} \mathrel{+}= \lambda - \kappa$ | Staking L1101–1106、L704–709、L1657–1663 | §25.5 |
| E38 | 资本重注 | $\rho = \min(\mathit{BD}, \mathit{PR})$，$\gamma = \min(a, \mathit{BD} - \rho)$；$\mathit{BD} \mathrel{-}= \rho + \gamma$ | Staking `absorbBadDebt`（L639–649） | §25.5 |
| E39 | 清算 | 当且仅当 $d_{u} > 0 \wedge (s_{u} = 0 \vee 100 d_{u} \ge 95 s_{u})$ 时可清算；$\mathrm{seized} = \min(d_{u} + \lfloor 500 d_{u}/10^{4} \rfloor, s_{u})$；损失为 $(d_{u} - s_{u})^{+}$ | Staking `_executeLiquidation`、`_isLiquidatable`（L1079–1137） | §25.5 |
| E40 | 紧急折减 | $x_{0} = (s_{u} - d_{u})^{+}$，$E' = E_{+} - e_{u} + x_{0}$；若 $\mathrm{pot} < E'$，则 $x = \lfloor x_{0}\,\mathrm{pot}/E' \rfloor$，否则为 $x_{0}$；$x \le \mathrm{pot}$ | Staking `emergencyWithdraw`（L689–696） | §25.5 |
| E41 | 借款上限 | $d_{u} + a \le \lfloor 50(s_{u} - d_{u})^{+}/100 \rfloor$ 且 $\lfloor (D + a) 10^{18}/S \rfloor \le 0.75 \cdot 10^{18}$ | Staking `borrow`、`_ltvCap`（L834–840、L1908–1909） | §25.5 |
| E42 | 维护预算 | 每个注册表 $c(n) = \min(1 + \lfloor n/50 \rfloor + \lfloor (t - t_{m})/900\ \mathrm{s} \rfloor,\ 10,\ n)$ | Staking `_windowBudget`（L1148–1157） | §25.5 |

## 附录 B · 不变量

以下性质在每个可达状态下都成立：每一条都由所列位置的代码形态强制执行，违反任何一条的交易都不会执行。INV-1–INV-18 沿用上一版的编号，强制执行一列已与代码对齐；INV-19–INV-22 为新增。INV-23–INV-31（2.3.0）属于质押引擎（§25），在质押仓库 `cc614f9` 处的 `src/BlazePhoenixStaking.sol` 中强制执行。

| # | 不变量 | 强制执行 |
|---|---|---|
| INV-1 | Router 在交易之间不持有任何资金；其静止余额为零。 | 以基线为范围的清扫与支付（§11）；`invariant_RouterHoldsNothing`、`HoldsNothingBeyondTheSeed` |
| INV-2 | 每次兑换都是原子的：不存在交易部分结算的状态。 | EVM 交易语义；单一帧 |
| INV-3 | 无预言机：没有任何外部价格源作为准入、排序、拆分、底线或费用的输入。 | 五个合约中不存在任何价格源调用 |
| INV-4 | 费率、费用分配与底线常量在已部署字节码中没有设置函数。 | Core 与 Router 中的编译期常量（§13） |
| INV-5 | 调用者提供的路由字段只能收紧保护，永远不能放宽。 | E16 三路取最大；覆盖闸门只会抬高证明值，永不降低（§11） |
| INV-6 | 最小值为零的兑换不会执行。 | 每个入口上的 `RouterE(10)` |
| INV-7 | Ψ 对候选进行排序和截断；没有任何报价、底线或分配读取它。 | 数据流：排序下游没有任何环节消费 Ψ（§9.6） |
| INV-8 | 一个交易对的注册表最多持有十六个池，驱逐按完整 Ψ 并以 E13 的裕度保留最适者。 | Hub `_canInsert`；`invariant_neverExceedsMaxSlots`（上限）；`test_RecordSwap_EvictsWeakestWhenFullAndNewcomerClearsMargin`（驱逐） |
| INV-9 | 没有运行时字节码的地址不会进入路由。 | 每次推导都检查 `hasCode`（§7） |
| INV-10 | 通用回调只向为当前分支承诺的池付款，只在分支执行期间付款，且付款永不超过该分支记录的预算。 | 瞬态分支上下文；池由 `RouterE(6)` 把关，预算由 `RouterE(8)` 把关（§11.4） |
| INV-11 | 地址声明了改动 delta 权限的 V4 钩子，会在任何代币移动之前被拒绝，且不会调用它。 | E18；`RouterE(9)`；Solver `_topKPools` |
| INV-12 | 任何定价乘积都不会溢出：每个危险乘法都经 512 位 `mulDiv` 分解，无法界定的状态报价为零。 | Core（§4.2、§6） |
| INV-13 | 舍入方向始终不利于过度承诺：报价与支付向下取整，保护性底线与费用向上取整。 | 各处的 Core `mulDiv` / `mulDivUp` |
| INV-14 | 在无法证明界限之处，计算返回零并放弃该交易场所——绝不猜测，也绝不在报价内部产生可被安排的回滚。 | 整个 Core 的失败即关闭姿态；`_solKFits`（§6） |
| INV-15 | 费用基数是实测的拉取量，以路由承诺的输入为上限——绝不是声明的输出；`route.totalOut` 不被任何代码读取。 | `_chargeHopFee`；`test_FeeBase_IgnoresLiedAboutTotalOut` |
| INV-16 | 放弃控制权是单向的：该标志只在一处被写为 `true`，没有任何地方写为 `false`；此后只剩下只增不减的策展人层级，已变动的工厂或钩子无法被重新启用。 | Hub 与 Router 上的 `renounceControl`（§14.7） |
| INV-17 | 声明的恒定乘积或 Solidly 回退费率只在 100 bps 上限内被采信；超出时以规范的 30 bps 为该池定价。 | E20 |
| INV-18 | 在 Solver 的方案中，没有一跳携带超过四个分支，没有一条路由超过十一个分支；Router 最多接受三跳、每跳五个分支。 | Solver 预算；Router `_execute` → `RouterE(3)` |
| INV-19 | 池只有在证明自己交易该交易对之后才能进入注册表：交易对形态的类型用 `token0()`/`token1()`，V4 则重新推导池 ID；被询问到的池在被发现过程列出之前也须作同样证明。 | Hub `recordSwap`、`_probe`；`invariant_ActiveEntriesTradeThePair` |
| INV-20 | 一次结算在锚定路由上恰好支付一次协议费，在穷尽路由上每跳支付一次；不存在未付任何费用的结算。 | 费用账本，`RouterE(15)`/`RouterE(16)`；`invariant_SettledSwapEmitsExactlyOneFee`（锚定）；`test/FeeSeals.t.sol`、`test/ExhaustionRegimePreviewParity.t.sol`（穷尽） |
| INV-21 | 各跳首尾相接——每一跳的输入是上一跳的输出——且无钩子分支不会在带钩子分支之后执行，无论在本跳还是任何后续跳（`sawHooked` 作用于整条路由）。 | Router `_execute` → `RouterE(3)`；`sawHooked` |
| INV-22 | 四个已部署合约——Hub、Solver、Router、Quoter——在 release 配置下均低于项目的 24,000 字节闸门发布，Core 库单独测量（24,576 中的 6,477 字节），测试套件也在该配置下运行。 | `DeployedSizeGate`；`profile_parity.py` |
| INV-23 | 在每个带有 `conserves` 的质押入口上，余额加债务加已记录坏账的变化量，与质押加两项储备加已分配未支付奖励的变化量相同，误差在 1e10 wei 以内（E35）。 | Staking `conserves`，L419–457 → `Staking__InvariantBreached` |
| INV-24 | 计划排放永不超过 `TOTAL_REWARDS − (TOTAL_REWARDS >> 8)`；累计注资永不超过 `TOTAL_REWARDS`；任何排放窗口支付的都不超过 `rewardReserve` 所持有的。 | `_emittedAt` L1458–1467；`fundEmission` L518 → `Staking__CapExceeded`；`_updateGlobal` L1442 |
| INV-25 | 每一笔已实现的损失——清算缺口、资不抵债的紧急退出、无法收回的利息——首先动用 `protocolReserve`；只有未覆盖的剩余部分才计入 `totalBadDebt`（E37）。 | Staking L1101–1106、L704–709、L1657–1663 |
| INV-26 | 当余额加 1e10 低于 `owed` 时，任何存入、借款、提取、奖励或纯收益领取、储备提取或紧急取消都不会执行（E36）。 | `_hardBreach` 把守 L760、L826、L902、L932、L948、L1510、L539、L620 → `Staking__InvariantBreached` |
| INV-27 | `absorbBadDebt` 不转出任何 BZPX，不向调用者支付任何东西，且使 `totalBadDebt` 的降幅至多为其当前值：先用储备，调用者的金额以未覆盖的剩余部分为上限（E38）。 | `absorbBadDebt` L639–649 |
| INV-28 | 排放权重、纯收益权重与正权益的总量只由 `_applyBoost` 写入，它把仓位已跟踪的项替换为重新计算的项；锁定只在有效期内获得加成（E30）。 | `_applyBoost` L1726–1734；`_effectiveLockDays` L1687–1690 |
| INV-29 | 借款只有在新债务至多为借款前仓位净质押的一半、且借款后账簿利用率至多为 75 % 时才会执行（E41）。 | `borrow` L834 → `Staking__LTVExceeded`；L838–840 → `Staking__UtilTooHigh` |
| INV-30 | 紧急退出支付的金额至多为仓位的净权益，且至多为合约的余额；当余额低于已跟踪权益时按 pot/E′ 缩放（E40）。 | `emergencyWithdraw` L689–696 |
| INV-31 | 在仓位最后一次存入后的 `MIN_DEPOSIT_BLOCKS` = 10 个区块内，任何提取、纯收益领取或锁定变更都不会执行。 | L894、L947、L971 → `Staking__FlashLoanProtection` |

## 附录 C · 复现命令

本文中来自仓库的每个数字都可由下列命令之一复现，前提是从 `Blaze-Phoenix-Dex` 在 `8949a9d` 处的干净检出出发，并已安装 Foundry 与 Python 3；分叉测试套件需要在 `DRPC_KEY` 中提供归档 RPC 密钥。

```bash
forge test --no-match-path 'test/fork/**'                        # the suite, release settings (§15.1)
forge test --match-path 'test/fork/**'                           # the fork lane, five chains (§15.1, §17)
FOUNDRY_PROFILE=release forge build --sizes --skip test --skip script   # sizes against EIP-170 (§16.3)
python3 .github/scripts/mutants.py                                # the curated mutation guard, 268/268 (§15.2)
python3 .github/scripts/check_targets.py                          # every mutant still points at one line
python3 .github/scripts/assurance/covering_array.py --check       # both covering arrays current (§15.4)
forge test --match-contract RegimeCoverageTest -vv                # strength 2, 63 rows
forge test --match-contract RegimeCoverageT3Test -vv              # strength 3, 168 rows
forge test --match-path test/regime/HostileVenueMatrix.t.sol      # ten pathologies × two doors (§15.5)
forge test --match-path test/regime/SandwichCurve.t.sol -vv       # the sandwich curve (§14.3)
forge test --match-path test/regime/CanonicalOracles.t.sol        # the quote maths against the specifications (§15.6)
forge test --match-path 'test/*MetamorphicRelations.t.sol'        # 14 + 5 relations (§15.7)
FOUNDRY_PROFILE=nver1 forge build --skip '*.t.sol' && FOUNDRY_PROFILE=nver2 forge build --skip '*.t.sol'
NVERSION_LANE=1 forge test --match-path 'test/nversion/*'         # the three binaries agree (§15.8)
forge test --match-test invariant_ --fuzz-seed 0xb1a2ef00          # the stateful campaigns (§15.3)
forge test --match-path test/FeeSeals.t.sol                       # the fee rule, both regimes (§13.4)
forge test --match-path test/QuoteDelayStatistics.t.sol -vv       # how a quote ages, 240 samples (§12.2)
forge test --match-path test/QuoterGasStatistics.t.sol -vv        # what a quote costs (§12.3)
forge test --match-path test/fork/QuoteDelayFork.t.sol -vv        # live Base, 1,000 USDC → WETH (§12.2)
forge test --match-path test/fork/FidelityMatrix.t.sol -vv        # preview → delivery, four chains (§17.2)
forge test --match-path test/fork/DiscoveryColdWarm.t.sol -vv     # cold and warm solve (§17.4)
forge test --match-path test/EquationBench.t.sol -vv              # ρ* (§17.6)
forge test --match-path 'test/fork/Deployed*.t.sol'               # what V1 is, pinned by codehash (§19)
python3 .github/scripts/assurance/projection_distance.py          # 86 / 99 (§15.9)
python3 .github/scripts/assurance/metrics.py                      # every assurance number, with its denominator
bash .github/scripts/shared-quantities.sh                         # the register agrees with the tree
```

算例 4 中的哈希可由任何 keccak-256 实现对 `abi.encode(currency0, currency1, fee, tickSpacing, hooks)` 计算复现；本文的数字由一个纯 Python 的 Keccak-f[1600] 实现生成，该实现已用空字符串与 `"abc"` 测试向量、以及 Core 硬编码的 `extsload(bytes32)` 选择器进行核验。

## 术语表

**算子。**

| 符号 | 名称 | 一句话 |
|---|---|---|
| Ω | 八重调度器 | 为每个分支定价——在闭式解精确之处用闭式解，在交易场所自身字节码是唯一可信来源之处向交易场所询问；“八重”源于历史，如今有六种在用类型 |
| 𝒟 | 确定性推导 | 在部署可复现之处用 CREATE2 算术计算池地址，在不可复现之处先询问再证明交易对，为 V4 单例合约推导并证明池 ID；`hasCode` 丢弃没有字节码的地址 |
| Φ | Iron-Law 底线 | 协议自身的保留底线：基准 96 %，随实测冲击与实测集中度放宽，硬性钳位于 80 %，作用于最后一跳的帧内报价 |
| Ψ | 活力场 | 仅由单槽（Monoslot）计算出的交易场所质量；对候选集进行排序和截断——它可以隐藏一个交易场所，但永远不会给它错误定价 |
| Ξ | 反诈骗投影算子 | 在排序之前、且不调用钩子的情况下，从最大化中移除任何触及改动 delta 或不可准入钩子的路由 |

**术语。** **锚定制度**——费用只收取一次，在 Router 持有的第一个桥接币上收取（或在直接进入桥接币的路由的输出上收取）。**可信带**——候选者边际汇率的深度加权中位数上下 ±5 %；候选集只有一个时不起作用。**覆盖闸门**——当证明值覆盖不到实测报价的一半时，将分支的证明界限抬高到实测报价。**Exact Pass**——Quoter 的池级精确预览：运行交易场所自身的兑换，再通过回滚提取（revert-extraction）将其回滚；自 2026-09-03 起为扣除费用后的净值。**穷尽制度**——没有任何一跳的输入是桥接币：每一跳按自身实测输入支付 28 bps；由构造保证对无价值的前缀免疫。**费用账本**——每次结算中费用支付次数的瞬态计数，拒绝零次，并在锚定路由上拒绝两次。**计量学设计**——把合约构建为一台仪器：将多样性压缩为坐标，测量每一个可测量的坐标，使其余坐标单调。**元方程**——把整个聚合器写成一次最大化，采用乘积形式，使任何一个失败的因子都让路由归零。**单槽（Monoslot）**——池的全部路由状态装在一个 256 位字中，其中不含价格。**单一回调原则**——一个 `fallback` 应答所有 V3 形态交易场所的闪电记账回调，并有三重守卫。**单向门**——以字节码实现的放弃控制权：控制层级消亡，只增不减的策展人层级保留。**交易对证明**——池在被注册表存储或被发现过程列出之前，先证明其 `token0`/`token1`（或其重新推导的 ID）。**投影距离**——一次拒绝所观察的对象与真正作出决定的对象之间相距多远。**自愈注册表**——协议通过交易来学习流动性：每个交易对十六个槽位、按适应度排序的驱逐、以算术实现的衰减。**盈余规则**——协议的抽成是某一个实测基数的 28 bps，不含任何随报价与交付之差而增长的部分。**第三种结果**——测试夹具的任何结果，既不是在各底线之内完成且 Router 上未留下任何东西的结算，也不是带有我们自己选择器的拒绝。

## 参考文献

1. G. Angeris, A. Evans, T. Chitra, S. Boyd. *Optimal Routing for Constant Function Market Makers.* arXiv:2204.05238, 2022 (ACM EC '22). ——将 CFMM 上的路由表述为凸规划；§10.4 的比例分配器所未达到的最优解。
2. T. Diamandis, M. Resnick, T. Chitra, G. Angeris. *An Efficient Algorithm for Optimal Routing Through Constant Function Market Makers.* arXiv:2302.04938, 2023 (Financial Cryptography 2023). ——同一问题的对偶分解算法（§23）。
3. H. Adams, N. Zinsmeister, D. Robinson. *Uniswap v2 Core.* 2020. https://uniswap.org/whitepaper.pdf ——恒定乘积的参考文献，以及 §4.2 中 30 bps 的默认值。
4. H. Adams, N. Zinsmeister, M. Salem, R. Keefer, D. Robinson. *Uniswap v3 Core.* 2021. https://uniswap.org/whitepaper-v3.pdf ——集中流动性、`slot0`、Q64.96 定点数（§4.2、§15.6）。
5. Uniswap Labs (H. Adams et al.). *Uniswap v4 Core.* 2024. https://uniswap.org/whitepaper-v4.pdf ——单例 PoolManager、闪电记账以及钩子权限的地址编码（§5、§14.2）。
6. M. Egorov. *StableSwap — Efficient Mechanism for Stablecoin Liquidity.* 2019. https://curve.fi/files/stableswap-paper.pdf ——§4.1 中被移除的那一族的放大不变量。
7. P. Daian, S. Goldfeder, T. Kell, Y. Li, X. Zhao, I. Bentov, L. Breidenbach, A. Juels. *Flash Boys 2.0: Frontrunning in Decentralized Exchanges, Miner Extractable Value, and Consensus Instability.* IEEE S&P 2020. DOI 10.1109/SP40000.2020.00040. ——§14.3 所约束、而非声称消除的排序对手。
8. L. Zhou, K. Qin, C. F. Torres, D. V. Le, A. Gervais. *High-Frequency Trading on Decentralized On-Chain Exchanges.* IEEE S&P 2021. DOI 10.1109/SP40001.2021.00027. ——对三明治攻击的测量与形式化（§14.3）。
9. P. Cousot, R. Cousot. *Abstract Interpretation: A Unified Lattice Model for Static Analysis of Programs by Construction or Approximation of Fixpoints.* POPL 1977. DOI 10.1145/512950.512973. ——将单 tick 闭式解视为可靠抽象的理论框架（§23）。
10. M. R. Clarkson, F. B. Schneider. *Hyperproperties.* Journal of Computer Security 18(6), 2010. DOI 10.3233/JCS-2009-0393. ——迹集合的性质；再分配类发现所属的类别（§21、§23）。
11. T. Y. Chen, S. C. Cheung, S. M. Yiu. *Metamorphic Testing: A New Approach for Generating Next Test Cases.* HKUST-CS98-01, 1998; arXiv:2002.12543. ——§15.7 的第二位裁判。
12. R. A. DeMillo, R. J. Lipton, F. G. Sayward. *Hints on Test Data Selection: Help for the Practicing Programmer.* IEEE Computer 11(4), 1978. DOI 10.1109/C-M.1978.218136. ——变异分析与耦合假设（§15.2）。
13. A. Avizienis. *The N-Version Approach to Fault-Tolerant Software.* IEEE TSE SE-11(12), 1985. DOI 10.1109/TSE.1985.231893. ——§15.8 的前身。
14. D. R. Kuhn, R. N. Kacker, Y. Lei. *Practical Combinatorial Testing.* NIST SP 800-142, 2010. DOI 10.6028/NIST.SP.800-142. ——覆盖数组与 t 路交互覆盖（§15.4）。
15. B. Littlewood, L. Strigini. *Validation of Ultrahigh Dependability for Software-Based Systems.* Communications of the ACM 36(11), 1993. DOI 10.1145/163359.163373. ——为何不给出正确性的概率（§15.11）。
16. A. Akhunov, M. Salem. *EIP-1153: Transient Storage Opcodes.* https://eips.ethereum.org/EIPS/eip-1153 ——分支上下文、费用账本与重入锁（§11.4、§13.2）。
17. V. Buterin. *EIP-170: Contract Code Size Limit.* https://eips.ethereum.org/EIPS/eip-170 ——24,576 字节的墙（§16.3）。
18. V. Buterin. *EIP-1014: Skinny CREATE2.* https://eips.ethereum.org/EIPS/eip-1014 ——𝒟 的地址算术（§7）。
19. M. Lundfall et al. *EIP-2612: Permit Extension for EIP-20 Signed Approvals.* https://eips.ethereum.org/EIPS/eip-2612 · Uniswap Labs. *Permit2.* https://github.com/Uniswap/permit2 ——Permit2 入口（§11.1）。
20. V. Buterin, S. Wilson, A. Dietrichs, M. Garnett. *EIP-7702: Set Code for EOAs.* https://eips.ethereum.org/EIPS/eip-7702 ——委托账户调用同样的入口（§11.1）。
21. *ERC-7201: Namespaced Storage Layout.* https://eips.ethereum.org/EIPS/eip-7201 ——Hub 的存储命名空间（§16.1）。
22. MariaDB Corporation Ab. *Business Source License 1.1.* https://mariadb.com/bsl11/ ——代码许可证。
23. Fable & Mitra. *BlazePhoenix-Dex: an on-chain DEX aggregator with measured routing.* Repository, `main` 8949a9d, 2026-09-05. https://github.com/blazephoenixxyz-crypto/Blaze-Phoenix-Dex ——本文每一项主张的规范来源；附录 C 从中复现各项数字。
24. S. Müller, N. Moumeni, A. Messaoudi. *Cost of Manipulation in AMM-Based Oracles.* arXiv:2606.03548, 2026 (Financial Cryptography 2026, DeFi workshop). ——E25 背后的流动性加权中位数界限（§10.3、§23）。
25. *Ormer: A Manipulation-resistant and Gas-efficient Blockchain Pricing Oracle for DeFi.* arXiv:2410.07893. ——一种估计中位数的链上预言机（oracle）（§23）。
26. *From Means to Medians: Optimal Benchmark Design.* arXiv:2506.22142. ——哪些基准最难被操纵（§23）。
27. *Optimal Routing across Constant Function Market Makers with Gas Fees.* arXiv:2603.02844. ——考虑 gas 的路由（§23）。
28. *Routing Frictions and Executable Liquidity in Fragmented Markets.* arXiv:2609.19013. ——宣称的流动性与可执行的流动性（§23）。

## 如何引用

Mitra. *BlazePhoenix Technical Whitepaper: an on-chain liquidity aggregator whose quote and execution are one computation.* Version 2.3.0, 2026-10-14. Zenodo. DOI [10.5281/zenodo.23084091](https://doi.org/10.5281/zenodo.23084091)（存档的 v2.3）。所有版本：[10.5281/zenodo.23084090](https://doi.org/10.5281/zenodo.23084090)。首个存档系列（v2.2）的概念 DOI：[10.5281/zenodo.22526574](https://doi.org/10.5281/zenodo.22526574)。BibTeX 及其他格式：https://blazephoenix.xyz/research/whitepaper
