> **Can't find what you're looking for?** Use `search_docs` on the docs MCP server at `https://www.steakhouse.financial/docs/api/mcp` to find what you need.

# MetaOracle（偏差时间锁）

该 `MetaOracleDeviationTimelock` 是一个安全封装器，用于在主预言机和备用预言机之间进行选择。当价格偏差持续超过阈值达整个挑战期时，它会切换到备用预言机；当价格持续重新收敛达恢复期后，它会切回主预言机。该合约实现了 Morpho 的 `IOracle` 接口，因此下游系统可以将其视为任何其他预言机。

### 部署

使用与网络相关的工厂地址来部署新的 MetaOracleDeviationTimelock 实例。

| 链        | MetaOracle 工厂                                                                                                                       |
| -------- | ----------------------------------------------------------------------------------------------------------------------------------- |
| Ethereum | [`0x44d049eEd4AD33807859C45bBd3a8eb47917a9F4`](https://etherscan.io/address/0x44d049eEd4AD33807859C45bBd3a8eb47917a9F4)             |
| Base     | [`0x507f940234005f7c49dfE2F27E361C3b66Fb31CF`](https://basescan.org/address/0x507f940234005f7c49dfE2F27E361C3b66Fb31CF)             |
| Arbitrum | [`0x4f3F56A045a2D33ceEf1D1fD5F4C776b8bFb2168`](https://arbiscan.io/address/0x4f3F56A045a2D33ceEf1D1fD5F4C776b8bFb2168)              |
| Katana   | [`0x53A30343c8A51d685d17c1c40AAe8e76D2B79b68`](https://katanascan.com/address/0x53A30343c8A51d685d17c1c40AAe8e76D2B79b68)           |
| Polygon  | [`0xd058Fc46edd745B6c883Ef3F775669039235753d`](https://polygonscan.com/address/0xd058Fc46edd745B6c883Ef3F775669039235753d)          |
| Monad    | [`0x1C1FD6dc5D84C16cD152aC2E91F80327FE3aEd9F`](https://monadvision.com/address/0x1C1FD6dc5D84C16cD152aC2E91F80327FE3aEd9F)          |
| Unichain | [`0xf1BaEC963675A367E3ADe06A531B6407D78ab2A3`](https://uniscan.xyz/address/0xf1BaEC963675A367E3ADe06A531B6407D78ab2A3)              |
| HyperEVM | [`0x9fAE9968e4e68bEE5ddcb48bb68Fb27CC57ff384`](https://explorer.hyperliquid.xyz/address/0x9fAE9968e4e68bEE5ddcb48bb68Fb27CC57ff384) |

浏览器链接反映的是当前公开的区块浏览器；如有需要，可替换为首选的区块浏览器。

### 审计与源码

* MetaOracleDeviationTimelock 源码： [MetaOracleDeviationTimelock.sol](https://github.com/Steakhouse-Financial/steakhouse-oracles/blob/36385342274f71999b66c79c4475234a39ba9a01/src/MetaOracleDeviationTimelock.sol)
* 工厂源码： [MetaOracleDeviationTimelockFactory.sol](https://github.com/Steakhouse-Financial/steakhouse-oracles/blob/36385342274f71999b66c79c4475234a39ba9a01/src/MetaOracleDeviationTimelockFactory.sol)
* 审计报告（Cantina）： [MetaOracleDeviationTimelock 审计报告](https://github.com/Steakhouse-Financial/steakhouse-oracles/blob/5ce0e80adb69bc06f5b390032150e7ea41d30c02/audits/2025-06-23-metaoracledeviationtimelock-cantina-managed-review.pdf)

### 核心行为

* 合约在初始化后会以主预言机作为默认选择。
* `price()` 返回当前处于激活状态的任一预言机（主预言机或备用预言机）的价格。
* 偏差的计算方式为 `abs(primary - backup) * 1e18 / average(primary, backup)`。
* 只有在经过带时间锁的挑战之后，偏差才可触发切换；只有在经过带时间锁的恢复之后，重新收敛才可触发切回。

### 流程图

**主 → 备（挑战）**

```mermaid
%%{init: {"theme":"base","themeVariables":{"background":"#fffdf1","primaryColor":"#ece7e1","primaryTextColor":"#1a1e20","primaryBorderColor":"#dedcd2","lineColor":"#515a5e","mainBkg":"#ece7e1","nodeBorder":"#dedcd2","clusterBkg":"#fffdf1","titleColor":"#1a1e20","edgeLabelBackground":"#fffdf1","arrowheadColor":"#086552","fontFamily":"Söhne, ui-sans-serif, system-ui, sans-serif","fontSize":"13px"},"flowchart":{"nodeSpacing":20,"rankSpacing":30}}}%%
flowchart LR
    Primary["主预言机已启用"] --> Deviate{"偏差是否超过阈值？"}
    Deviate -- "否" --> Primary
    Deviate -- "是" --> Challenge["challenge() 启动时间锁"]
    Challenge --> ChallengeEnd{"challengeTimelockDuration 结束后"}
    ChallengeEnd -- "偏差已消除" --> Primary
    ChallengeEnd -- "仍存在偏差" --> Backup["acceptChallenge() → 备用预言机"]



```

**备 → 主（恢复）**

```mermaid
%%{init: {"theme":"base","themeVariables":{"background":"#fffdf1","primaryColor":"#ece7e1","primaryTextColor":"#1a1e20","primaryBorderColor":"#dedcd2","lineColor":"#515a5e","mainBkg":"#ece7e1","nodeBorder":"#dedcd2","clusterBkg":"#fffdf1","titleColor":"#1a1e20","edgeLabelBackground":"#fffdf1","arrowheadColor":"#086552","fontFamily":"Söhne, ui-sans-serif, system-ui, sans-serif","fontSize":"13px"},"flowchart":{"nodeSpacing":20,"rankSpacing":30}}}%%
flowchart LR
    Backup["备用预言机已启用"] --> Reconverge{"价格是否已重新收敛？"}
    Reconverge -- "否" --> Backup
    Reconverge -- "是" --> Heal["heal() 启动时间锁"]
    Heal --> HealEnd{"healingTimelockDuration 结束后"}
    HealEnd -- "偏差再次出现" --> Backup
    HealEnd -- "仍保持收敛" --> Primary["acceptHealing() → 主预言机"]
```

### 参数

* `primaryOracle`：正常情况下使用的首选预言机。
* `backupOracle`：偏差期间使用的备用预言机。
* `deviationThreshold`：允许的最大相对偏差，按 `1e18` 缩放（例如，`0.01e18` 表示 1%）。
* `challengeTimelockDuration`：切换到备用预言机之前，偏差必须持续的秒数。
* `healingTimelockDuration`：切回主预言机之前，价格必须保持重新收敛的秒数。

初始化会拒绝零地址、相同的预言机地址、非正阈值，以及任何高于 `deviationThreshold` 的初始偏差。

### 挑战流程（主 → 备）

1. 任何人都可以在主预言机处于激活状态且价格出现偏差时调用 `challenge()`。
2. 合约会启动挑战时间锁（`challengeExpiresAt`）。
3. 如果在到期前价格重新收敛，任何人都可以调用 `revokeChallenge()`。
4. 到期后，只要偏差仍然存在，任何人都可以调用 `acceptChallenge()` 切换到备用预言机。

### 恢复流程（备 → 主）

1. 任何人都可以在备用预言机处于激活状态且价格已经重新收敛时调用 `heal()`。
2. 合约会启动恢复时间锁（`healingExpiresAt`）。
3. 如果在到期前价格再次出现偏差，任何人都可以调用 `revokeHealing()`。
4. 到期后，只要价格仍然保持收敛，任何人都可以调用 `acceptHealing()` 切回主预言机。

### 示例：XAUT/USDT 市场

**设置**

* 主预言机：XAUT 价格来自 XAU（黄金）参考馈送，USDT 固定为 `1`。
* 备用预言机：XAUT/USDT 市场 TWAP（两个价格端都采用市场定价）。

**流程**

1. 只要黄金参考价格与 XAUT 市场价格接近，MetaOracle 就会使用主预言机。
2. 如果 XAUT 的交易价格偏离黄金参考（或 USDT 出现漂移），偏差会超过阈值，`challenge()` 会启动时间锁。
3. 如果偏差在挑战时间锁期间持续存在，`acceptChallenge()` 会将定价切换到市场 TWAP 备用预言机。
4. 一旦市场价格在恢复时间锁期间与黄金参考重新收敛，`acceptHealing()` 会切回主预言机。

```mermaid
%%{init: {"theme":"base","themeVariables":{"background":"#fffdf1","primaryColor":"#ece7e1","primaryTextColor":"#1a1e20","primaryBorderColor":"#dedcd2","secondaryColor":"#ece7e1","tertiaryColor":"#fffdf1","lineColor":"#515a5e","textColor":"#1a1e20","mainBkg":"#ece7e1","nodeBorder":"#dedcd2","clusterBkg":"#fffdf1","titleColor":"#1a1e20","edgeLabelBackground":"#fffdf1","arrowheadColor":"#086552","fontFamily":"Söhne, ui-sans-serif, system-ui, sans-serif"}}}%%
sequenceDiagram
    participant User as 任意调用者
    participant Meta as MetaOracle
    participant Primary as "主预言机（XAU 参考价，USDT=1）"
    participant Backup as "备用预言机（XAUT/USDT TWAP）"

    Note over Meta: 初始使用主预言机
    Meta->>Primary: price()
    User->>Meta: challenge()：偏差 > 阈值
    Note over Meta: 等待 challengeTimelockDuration
    User->>Meta: acceptChallenge()：偏差仍存在
    Note over Meta: 切换至备用预言机
    Meta->>Backup: price()
    User->>Meta: heal()：价格重新收敛
    Note over Meta: 等待 healingTimelockDuration
    User->>Meta: acceptHealing()：价格仍保持收敛
    Note over Meta: 切回主预言机
    Meta->>Primary: price()

```

### 工厂

MetaOracleDeviationTimelock 实例由 `MetaOracleDeviationTimelockFactory` 使用 EIP-1167 克隆进行部署。每次部署都会发出 `MetaOracleDeployed` 事件，其中包含代理地址、实现合约、预言机对、阈值和时间锁持续时间。
