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.

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

Audit and source

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)

spinner

Backup → primary (healing)

spinner

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.

spinner

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.

Last updated