> For the complete documentation index, see [llms.txt](https://docs.chiliz.com/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://docs.chiliz.com/develop/advanced/get-asset-and-fan-token-prices/best-practices.md).

# Best practices

## Always Validate Before Using a Price

`latestRoundData()` reverts with `NoDataAvailable()` if no rounds exist, but does not enforce staleness or pause checks: it returns stored values as-is. Before consuming any price value, always perform these three checks:

1. **Pause check**: call `paused()` and reject if the feed is paused.
2. **Positive answer**: require `answer > 0`.
3. **Staleness check**: gate on `getHealthStatus().isHealthy`.

The `getSafePrice()` example in [Reading Prices](/develop/advanced/get-asset-and-fan-token-prices/reading-prices.md) implements all three.

## Health Status API

Each `PriceFeed` exposes a `getHealthStatus()` view that aggregates freshness information in a single call:

```solidity
function getHealthStatus()
    external view
    returns (
        uint256 lastUpdateTimestamp,
        uint256 totalRounds,
        uint256 timeSinceLastUpdate,
        bool isHealthy
    );
```

| Field                 | Description                                                               |
| --------------------- | ------------------------------------------------------------------------- |
| `lastUpdateTimestamp` | `updatedAt` of the most recent round                                      |
| `totalRounds`         | Total number of rounds written                                            |
| `timeSinceLastUpdate` | `block.timestamp - lastUpdateTimestamp` (or `block.timestamp` if no data) |
| `isHealthy`           | `true` if `timeSinceLastUpdate <= updateInterval × healthFactor`          |

The health factor is initialised to `2` by default but is configurable per feed by the oracle admin via `setHealthFactor()`. Do not hardcode `2`. Read it directly from the contract:

```solidity
uint80 factor = priceFeed.healthFactor(); // per-feed; do NOT assume the default of 2 (live feeds use 720)
```

The health window is `updateInterval × healthFactor`, both configured per feed. `updateInterval` is a small on-chain minimum spacing, not the heartbeat. It varies per feed: CHZ/USDC uses `5s × 720 = 1-hour` window, PEPPER/CHZ uses `10s × 720 = 2-hour` window, while the off-chain pipeline pushes on a \~1-hour heartbeat. Never use `updateInterval` alone as a staleness baseline; gate on `isHealthy`. See `getSafePrice()` in [Reading Prices](/develop/advanced/get-asset-and-fan-token-prices/reading-prices.md) for the full pattern.

Use `getAllOracleHealthStatus()` on the `OracleFactoryReader` to monitor every feed in the system at once (useful for off-chain dashboards and alerting).

## Cache `decimals()`

Each pair has its own decimal precision: always call `decimals()` to confirm before interpreting a price value. Decimals are set at deployment and never change, so read them once at contract initialisation rather than on every price read:

```solidity
uint8 public immutable feedDecimals;

constructor(address _feed) {
    priceFeed = IChilizPriceFeed(_feed);
    feedDecimals = priceFeed.decimals();
}
```

## Handle the Paused State Gracefully

In an emergency, the oracle manager can pause a feed. Handle the resulting revert cleanly rather than silently consuming a bad value:

```solidity
require(!priceFeed.paused(), "Feed paused");
```

## Use the Tracker During Development

The [Price Oracle Tracker](https://price-oracle-tracker.vercel.app/?network=mainnet) lets you compare on-chain prices against CoinMarketCap and CoinGecko in real time, making it easy to validate feed accuracy during integration. It also shows live health status, heartbeat parameters, and individual contract addresses for every pair.

## Integration Checklist

* [ ] Obtain the `PriceFeed` address via the tracker, `pairToOracle()`, or `getActiveOracles()`
* [ ] Confirm the pair description and decimals using `description()` and `decimals()`
* [ ] Cache `decimals()` at contract initialisation
* [ ] Read prices via `latestRoundData()` (reverts with `NoDataAvailable()` if no rounds exist yet)
* [ ] Check `paused()` before consuming a price
* [ ] Validate `answer > 0`
* [ ] Gate on `getHealthStatus().isHealthy` for staleness (do not derive your own threshold from `updateInterval` alone)
* [ ] Normalise the price to your internal precision (e.g. 18 decimals) if needed
* [ ] Test on Spicy Testnet before deploying to Mainnet


---

# 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://docs.chiliz.com/develop/advanced/get-asset-and-fan-token-prices/best-practices.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.
