> ## Documentation Index
> Fetch the complete documentation index at: https://docs.li.fi/llms.txt
> Use this file to discover all available pages before exploring further.

# Guards

> compose 服务如何在链上模拟一个 flow，以及 guards 如何将模拟观测转化为可强制执行的不变量。

> 在[执行模型](/composer/composer-api/concepts/execution-model)中，模拟步骤会观测运行时值。Guards 就是这些观测变成链上断言的方式。

在一个 flow 被降级为可执行程序之后，compose 服务会**在**返回 calldata **之前**，针对目标链的最新状态（当前链头）对其进行模拟。此模拟产生三样东西：每个终端资源的值（以便填充 `producedResources`）、每个被 guard 要求观测的 handle 的值，以及一个 gas 估算。Guards 就是把那些观测到的值转化为烘焙进交易本身的链上不变量的机制。

## guard 是什么

**guard** 是附加到某个 op 输出上的不变量。服务在模拟期间读取相关的 port 值，然后将相应的检查烘焙进编译后的 calldata，以便在交易运行时于链上强制执行该不变量。

Guards 不是可以被悄悄放宽的模拟期检查。该检查是最终 calldata 的一部分，并在交易运行时于链上被验证，因此 calldata 本身即保证了该不变量。

## guards 何时运行

Guards 在 compose 流水线的**模拟与断言**步骤中触发（参见 [Execution model](/composer/composer-api/concepts/execution-model)）。具体来说：

* 服务针对当前链头模拟该程序，读取 guards 所观测的任何链上值。模拟器会返回每个被观测 port 的具体值。
* 对于每个 guard，被观测的值会被烘焙进一个强制执行该不变量的检查中。该检查是最终编译程序的一部分。
* 最终 calldata 会再次针对服务的策略（合约白名单、转账模式、指令数上限）进行验证。

如果被模拟的程序回滚，或断言无法被满足，编译会以 `guard_error`（HTTP 422）失败，并且不返回任何 calldata。在 `simulationPolicy: "allow-revert"` 下，calldata 会以 HTTP 206 连同回滚诊断信息一起返回。

## guards 可以附加到哪里：`providesMinimum` port

guard 声明一个 `compatibility.selectors` 列表，描述它可以附加到哪些 port。编译期校验器会拒绝对它无法保护的 port 的附加。特别地：

* 已经声明 `providesMinimum: true` 的 port（路由器或聚合器已经烘焙进一个最小输出）**不能**携带冗余的最小输出 guard。对这类 port 附加一个 `slippage` guard 会在编译期产生一个 `guard_error`，消息为 *"Guard targets port … which provides its own minimum"*。
* `lifi.swap` 的 `amountOut` port 是典型例子：LI.FI 的聚合器已从 `slippage` 配置字段编码了 `minOut`，因此你不需要（也不能）再对它附加第二个滑点 guard。
* `lifi.zap` 的 `amountOut` **不**提供它自己的最小值，这就是为什么 [swap-and-zap recipe](/composer/composer-api/recipes/swap-and-zap) 会在那里附加一个 `slippage` guard。

使用 op 的 manifest 来查看哪些输出 port 携带 `providesMinimum`；当你需要以编程方式进行判别时，使用 [References](/composer/composer-api/concepts/ref-grammar) 和 port 类型守卫。

## 保证的最小值与 `amountOutMin`

某些 guard（例如 `slippage`）还会产生一个**保证的最小值**：给定该 guard 的容差，被观测 port 的最坏情况值。对于任何其输出 port 受此类 guard 保护的终端资源，服务会在响应上以 `producedResources[*].simulated.amountOutMin` 的形式呈现该值。如果你对同一个 port 附加多个 guard，则最紧的最小值（最大的那个）胜出。

这就是为什么 guard 是编码安全边界的正确位置：你给 guard 的同一个容差值，既会成为一个链上断言，**也会**成为响应上一个用户可见的字段，因此你的 UI 可以直接显示"你将至少收到 X"，而无需重新计算任何东西。

## 常见的 guard 失败

| 失败                                                                                                     | 原因                                                                   |
| ------------------------------------------------------------------------------------------------------ | -------------------------------------------------------------------- |
| `Guard targets port "<p>" which provides its own minimum`                                              | 对一个其 op 已声明 `providesMinimum` 的 port 附加了最小输出式的 guard。移除该 guard。      |
| `Guard targets port "<p>" which does not exist`                                                        | guard 配置中的 port 名称与该 op 上的任何 port 都不匹配。检查该 op 的 manifest。            |
| `Guard requires config field "<key>"`                                                                  | guard selector 使用了 `selection: { kind: "config" }`，而 config 缺少该 key。 |
| `Guard '<kind>' on '<call>' returned guaranteedMinimums key '<p>' which is not in its observedHandles` | 某个第三方 guard 定义中的内部 bug；请向上游报告。                                       |
| 模拟期的 `guard_error`                                                                                     | 被模拟的交易会违反该不变量。放宽容差或调查该报价。                                            |

## guards **不**做的事

* **Guards 不替代前置条件。** [前置条件（Preconditions）](/composer/composer-api/guides/build-a-flow#preconditions-state-before-execution)描述在交易运行**之前**必须为真的链上状态（例如，"用户持有至少 X USDC"），并作为状态覆盖馈送给模拟器。Guards 在交易**期间**运行，并对计算得出的值强制执行不变量。
* **Guards 不改变路由。** 一个在用户请求的容差下会失败的滑点 guard 会以 `guard_error` 的形式暴露；服务不会悄悄地重新路由。如果你想让聚合器遵守该容差，请在 op 上配置它（例如 `lifi.swap` 的 `slippage` 字段）。
* **Guards 不在链上运行任意用户代码。** guard 使用一组有界的、经过审计的检查来强制执行其不变量 —— 它无法在链上执行任意逻辑。

## 另请参阅

* [Guards catalog](/composer/composer-api/guards) —— manifest 中注册的每一个 guard。
* [Build a Flow → Add safety](/composer/composer-api/guides/build-a-flow#add-safety-preconditions-and-guards) —— 如何将 guards 和前置条件附加到 flow。
* [Execution Model](/composer/composer-api/concepts/execution-model) —— 模拟步骤在流水线中的位置。
