> For the complete documentation index, see [llms.txt](https://steakhouse.financial/docs/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://steakhouse.financial/docs/products/infrastructure/metaoracle.md).

# MetaOracle (Deviation Timelock)

The `MetaOracleDeviationTimelock` is a safety wrapper that selects between a primary and backup oracle. It switches to the backup when prices diverge beyond a threshold for a sustained challenge period, and switches back to the primary after prices reconverge for a sustained healing period. The contract implements Morpho’s `IOracle` interface, so downstream systems can treat it like any other oracle.

### Deployments

Use the network-specific factory addresses to deploy new MetaOracleDeviationTimelock instances.

| Chain    | MetaOracle factory                                                                                                                  |
| -------- | ----------------------------------------------------------------------------------------------------------------------------------- |
| 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) |

Explorer links reflect current public explorers; swap in preferred explorers if needed.

### Audit and source

* MetaOracleDeviationTimelock source: [MetaOracleDeviationTimelock.sol](https://github.com/Steakhouse-Financial/steakhouse-oracles/blob/36385342274f71999b66c79c4475234a39ba9a01/src/MetaOracleDeviationTimelock.sol)
* Factory source: [MetaOracleDeviationTimelockFactory.sol](https://github.com/Steakhouse-Financial/steakhouse-oracles/blob/36385342274f71999b66c79c4475234a39ba9a01/src/MetaOracleDeviationTimelockFactory.sol)
* Audit report (Cantina): [MetaOracleDeviationTimelock audit report](https://github.com/Steakhouse-Financial/steakhouse-oracles/blob/5ce0e80adb69bc06f5b390032150e7ea41d30c02/audits/2025-06-23-metaoracledeviationtimelock-cantina-managed-review.pdf)

### Core behavior

* The contract starts with the primary oracle selected after initialization.
* `price()` reflects whichever oracle is active (primary or backup).
* Deviation is computed as `abs(primary - backup) * 1e18 / average(primary, backup)`.
* A deviation can only trigger a switch after a timelocked challenge; reconvergence can only trigger a switch back after a timelocked healing.

### Flow diagram

**Primary → backup (challenge)**

{% @mermaid/diagram content="%%{init: {'themeVariables': {'fontSize': '13px'}, 'flowchart': {'nodeSpacing': 20, 'rankSpacing': 30}}}%%
flowchart LR
Primary\["Primary active"] --> Deviate{"Deviation > threshold?"}
Deviate -- "No" --> Primary
Deviate -- "Yes" --> Challenge\["challenge() starts timelock"]
Challenge --> ChallengeEnd{"After challengeTimelockDuration"}
ChallengeEnd -- "Deviation cleared" --> Primary
ChallengeEnd -- "Still deviant" --> Backup\["acceptChallenge() -> backup"]

" %}

**Backup → primary (healing)**

{% @mermaid/diagram content="%%{init: {'themeVariables': {'fontSize': '13px'}, 'flowchart': {'nodeSpacing': 20, 'rankSpacing': 30}}}%%
flowchart LR
Backup\["Backup active"] --> Reconverge{"Prices reconverged?"}
Reconverge -- "No" --> Backup
Reconverge -- "Yes" --> Heal\["heal() starts timelock"]
Heal --> HealEnd{"After healingTimelockDuration"}
HealEnd -- "Deviation returns" --> Backup
HealEnd -- "Still converged" --> Primary\["acceptHealing() -> primary"]" %}

### Parameters

* `primaryOracle`: preferred oracle used in normal conditions.
* `backupOracle`: fallback oracle used during deviation periods.
* `deviationThreshold`: maximum allowed relative deviation, scaled by `1e18` (e.g., `0.01e18` for 1%).
* `challengeTimelockDuration`: seconds a deviation must persist before switching to backup.
* `healingTimelockDuration`: seconds prices must remain reconverged before switching back to primary.

Initialization rejects zero addresses, equal oracle addresses, non-positive thresholds, and any initial deviation above `deviationThreshold`.

### Challenge flow (primary → backup)

1. Anyone calls `challenge()` when the primary is active and prices are deviant.
2. The contract starts a challenge timelock (`challengeExpiresAt`).
3. If prices reconverge before expiry, anyone can call `revokeChallenge()`.
4. After expiry, anyone can call `acceptChallenge()` while deviation still holds to switch to the backup.

### Healing flow (backup → primary)

1. Anyone calls `heal()` when the backup is active and prices have reconverged.
2. The contract starts a healing timelock (`healingExpiresAt`).
3. If prices deviate again before expiry, anyone can call `revokeHealing()`.
4. After expiry, anyone can call `acceptHealing()` while prices are still converged to switch back to the primary.

### Example: XAUT/USDT market

**Setup**

* Primary oracle: XAUT priced from the XAU (gold) reference feed, USDT fixed at `1`.
* Backup oracle: XAUT/USDT market TWAP (both legs from market pricing).

**Flow**

1. As long as the gold reference and the XAUT market price are close, the MetaOracle uses the primary oracle.
2. If XAUT trades away from the gold reference (or USDT drifts), the deviation exceeds the threshold and `challenge()` starts the timelock.
3. If the deviation persists through the challenge timelock, `acceptChallenge()` switches pricing to the market TWAP backup.
4. Once the market price reconverges with the gold reference for the healing timelock, `acceptHealing()` switches back to the primary.

{% @mermaid/diagram content="sequenceDiagram
participant User as Any caller
participant Meta as MetaOracle
participant Primary as "Primary (XAU ref, USDT=1)"
participant Backup as "Backup (XAUT/USDT TWAP)"

```
Note over Meta: Starts on primary
Meta->>Primary: price()
User->>Meta: challenge() when deviation > threshold
Note over Meta: Wait challengeTimelockDuration
User->>Meta: acceptChallenge() if still deviant
Note over Meta: Switches to backup
Meta->>Backup: price()
User->>Meta: heal() when prices reconverge
Note over Meta: Wait healingTimelockDuration
User->>Meta: acceptHealing() if still converged
Note over Meta: Switches back to primary
Meta->>Primary: price()
```

" %}

### Factory

MetaOracleDeviationTimelock instances are deployed by `MetaOracleDeviationTimelockFactory` using EIP-1167 clones. Each deployment emits `MetaOracleDeployed` with the proxy address, implementation, oracle pair, threshold, and timelock durations.


---

# Agent Instructions
This documentation is published with GitBook. GitBook is the documentation platform designed so that both humans and AI agents can read, navigate, and reason over technical content effectively. Learn more at gitbook.com.

## Querying This Documentation
If you need additional information that is not directly available in this page, you can query the documentation dynamically by asking a question.

Perform an HTTP GET request on the current page URL with the `ask` query parameter, and the optional `goal` query parameter:

```
GET https://steakhouse.financial/docs/products/infrastructure/metaoracle.md?ask=<question>&goal=<endgoal>
```

`ask` is the immediate question: it should be specific, self-contained, and written in natural language.
`goal` is optional and describes the broader end goal you are ultimately trying to accomplish on behalf of the user. GitBook uses it to tailor the answer towards what is most useful for that goal.

The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
