> For the complete documentation index, see [llms.txt](https://docs.tapir.money/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://docs.tapir.money/protocol-mechanics/tapir-mechanics/oracle-resolution.md).

# Oracle Resolution

Tapir's oracle records price observations and supplies a high watermark and a closing price. The **DepegPool** compares these values and fixes DP and YB redemption rates. A temporary market dip does not automatically trigger a payout.

## One market, one configured oracle

| Protected exposure     | Oracle                                                                              | Additional signal                                               |
| ---------------------- | ----------------------------------------------------------------------------------- | --------------------------------------------------------------- |
| Pegged asset           | Base oracle                                                                         | Configured on-chain price feeds                                 |
| ERC-4626 vault share   | [VRP Oracle](/protocol-mechanics/tapir-mechanics/oracle-resolution/vrp-oracle.md)   | The vault's `previewRedeem` value; adjusts both final prices    |
| Pendle Principal Token | [PTRW Oracle](/protocol-mechanics/tapir-mechanics/oracle-resolution/ptrw-oracle.md) | A redemption witness after PT expiry; adjusts the closing price |

VRP and PTRW inherit the base price-history machinery. The feeds and reference asset must match the market's configuration; neither extension removes dependence on those feeds.

## Who records and submits prices?

Accounts with `OPERATOR_ROLE` record the enabled sources, create checkpoints, and call `writePriceData`. These operations require an unpaused oracle. An off-chain keeper can automate the calls, but collection and submission are **permissioned**, not self-executing.

An oracle administrator can change sources and configuration and pause or unpause the oracle. Pool administrators can propose a replacement oracle with a **seven-day timelock**. Anyone can execute that replacement after the delay. These controls are part of the protocol's trust model.

## Source selection

The base oracle reads configured on-chain interfaces for **API3, Chainlink, RedStone Classic, and Tellor**. A market need not use all four. It normalizes prices to the configured asset decimals and applies source positivity, timestamp, freshness, and enabled-source checks.

A checkpoint requires the configured minimum number of valid sources, from one to four:

| Valid sources | Checkpoint price                                                                            |
| ------------- | ------------------------------------------------------------------------------------------- |
| 1             | That source's value                                                                         |
| 2             | The value closer to the previous checkpoint; their average if no previous checkpoint exists |
| 3             | Median                                                                                      |
| 4             | Average of the middle two values                                                            |

For example, `[1.00, 1.01, 0.70]` gives `1.00`, but `[1.00, 0.70, 0.71]` gives `0.71`. Multiple sources reduce reliance on one feed; correlated errors and low source counts can still affect settlement. The contract does not directly calculate a market TWAP or query an off-chain dispute service.

## Sampling and daily prices

The contract enforces `minCheckpointSpacing`. It does **not** require exactly one checkpoint per day or enforce a UTC sampling window.

The documented operating convention is roughly daily sampling, with a random primary attempt between `14:30–16:30 UTC`, retries when needed, and a randomized fallback between `16:30–17:30 UTC`. This is keeper policy. It depends on the operator continuing to run the required transactions.

Each checkpoint records the selected price with the block timestamp when `checkpoint()` succeeds. Calculations later group checkpoints by UTC calendar day:

| Checkpoints in a selected day | Daily representative price |
| ----------------------------- | -------------------------- |
| 1                             | That price                 |
| 2                             | The lower price            |
| 3 or more                     | Their median               |

For example, `[0.99, 1.01, 1.00]` on one day becomes `1.00`.

## High watermark

The high watermark (HWM) filters upward spikes using consecutive triplets of daily representatives:

```
buffer HWM = max(min(p[i], p[i+1], p[i+2]))
written HWM = max(persistedHwm, buffer HWM)
```

Example:

```
Daily representatives: [1.00, 1.10, 1.02, 1.01, 0.98]
Triplet minimums:      [1.00, 1.01, 0.98]
Buffer HWM:            1.01
```

The `1.10` spike does not set the HWM. A fresh base oracle normally needs observations on **three distinct UTC days** before it can produce its first non-zero HWM. These are consecutive observed days; the contract does not require observations on every intervening calendar day or prove that a price held continuously for 72 hours.

The ring buffer holds **400 raw checkpoints**. When a checkpoint starts a new UTC day, the oracle first persists any higher HWM from the existing buffer. The persisted HWM never decreases, preserving earlier qualifying highs after checkpoints roll out of the buffer.

## Closing price

The closing price is a median of daily representatives derived from a configurable selection of recent checkpoints:

1. Count raw checkpoints strictly inside `closingPriceLookbackPeriod`, measured when prices are written.
2. Request that many checkpoints, with a minimum request of five. If fewer than five exist, use those available.
3. Group the selected checkpoints by UTC day using the daily rule above.
4. Take the median of those daily representatives.

```
closing price = median(selected daily representatives)
```

This is **not a fixed five-day window**. A longer lookback can select more than five raw checkpoints; several checkpoints on one day can yield fewer than five daily representatives. If fewer than five checkpoints fall inside the lookback, older checkpoints can be included. The contract also does not force the selected observations to stop exactly at maturity.

For the following examples, assume one checkpoint per day, selection of exactly the latest five checkpoints, and no higher persisted HWM:

| Daily prices over the pool                   | HWM  | Closing price | Outcome                |
| -------------------------------------------- | ---- | ------------- | ---------------------- |
| `[1.00, 1.01, 1.02, 1.03, 1.04, 1.05, 1.06]` | 1.04 | 1.04          | No depeg               |
| `[1.00, 1.00, 1.00, 0.82, 0.80, 0.79, 0.78]` | 1.00 | 0.80          | 20% depeg              |
| `[1.00, 1.00, 1.00, 1.00, 0.99, 1.01, 0.70]` | 1.00 | 1.00          | Final dip filtered out |

Smoothing reduces the influence of isolated readings, and can also omit a short-lived real loss. More frequent checkpoints do not automatically mean more independent days of evidence.

## Submission and settlement

```
Active → Cooldown → Resolution → Redemptions
```

| Stage       | What happens                                                                                                   |
| ----------- | -------------------------------------------------------------------------------------------------------------- |
| Active      | Users can split and unsplit while the pool is unpaused; operators collect oracle data.                         |
| Cooldown    | Split, unsplit, and redemption are unavailable. The configured oracle submits both final prices together.      |
| Resolution  | Cooldown has elapsed and prices have been submitted. Anyone can resolve once the submitted data is old enough. |
| Redemptions | DP and YB redeem at the fixed rates while the pool is unpaused.                                                |

Both `cooldownDuration` and `minPriceAge` are configured between **four hours and 30 days**. The earliest settlement is:

```
max(active end + cooldownDuration, latest price submission + minPriceAge)
```

The configured oracle can replace submitted data while the pool remains in Cooldown. Each replacement restarts the price-age clock. The admin can change cooldown duration during Active, and minimum price age during Active or Cooldown. Once `resolvePriceDepeg()` succeeds, the pool's redemption rates cannot be changed.

Pool lifecycle restrictions apply to pool operations. DP/YB transfers and direct swaps on an external AMM are not automatically stopped by the pool's maturity or pause controls.

The pool accepts an HWM within its immutable `[MIN_PRICE, MAX_PRICE]` range and a closing price between zero and `MAX_PRICE`. Base and PTRW oracles support same-chain or configured cross-chain delivery. Cross-chain submission depends on the configured messenger and authenticated oracle sender. VRP supports **same-chain delivery only**.

## Depeg calculation and payouts

The pool detects a depeg when the closing price is lower than the HWM and the drop is at least:

```
minimum drop = floor(HWM × 10 / 10,000)
```

This is nominally **0.1%**, with integer rounding at the configured price scale. The threshold rounds to zero when the integer HWM is below 1,000, so price-scale configuration matters.

For a detected depeg:

```
principalDepeggedValue = floor(closing price × 10,000 / HWM)
depegSize = 10,000 − principalDepeggedValue
DP value = min(20,000, floor(100,000,000 / principalDepeggedValue))
YB value = 20,000 − DP value
```

Values are in basis points: 10,000 means one base token per derivative token. When `principalDepeggedValue` is zero, DP is set directly to 20,000 and YB to zero. With no depeg, both values are 10,000.

For a 20% depeg, DP redeems at 125% and YB at 75%. At a 50% or greater depeg, DP reaches its 200% cap and YB falls to zero. These are **base-token redemption amounts before fees**, not guaranteed returns in dollars. See [Depeg Risk Splitting](/protocol-mechanics/tapir-mechanics/depeg-risks-splitting.md).

For implementation and access-control references, see [Source Code & Contracts](/resources/source-code-and-contracts.md).
