A Pyth price update carries a timestamp from the moment the aggregate was signed on Pythnet. After it's posted on-chain by a relayer, time keeps passing — but the on-chain record doesn't update by itself. A consumer that reads it ten minutes later is still seeing the old price. Pyth's design assumes the consumer is going to check the publish time and decide whether it's fresh enough to act on.
Why this matters
Stale prices are the most common way oracle integrations get exploited. A liquidation engine that doesn't check freshness will happily liquidate against a price that hasn't updated since the asset moved twenty percent. A perpetuals exchange that ignores it will mispay funding. The exploit vector is almost always 'attacker times their action against an unrefreshed read.'
How Pyth helps
- The Solidity and Rust SDKs expose get_price_no_older_than(max_age) — refuses the read if the publish time is too old
- Update fees are designed to be small enough that bundling a fresh update into the consuming transaction is always affordable
- The pull model means a contract that doesn't trust the on-chain copy can always force a refresh before acting
Recommended pattern
- 01Before any state-changing action, pull a fresh update into the same transaction.
- 02Check both publish time (within your max_age) and confidence interval (within your tolerance).
- 03Fail the transaction if either check is off — don't fall back to the previous on-chain value silently.
What to look for on Pythscan
Each feed page surfaces a 'published Xs ago' caption under the live price. If you see a very old timestamp on a feed that should be active, that's the same signal a consumer contract would see. Pythscan also marks feeds the on-chain status flag classifies as inactive.