Chainlink Data Feeds (Hedera)
Push feed pattern: a Chainlink aggregator is updated off-chain; on-chain readers call latestRoundData() and must reject incomplete, non-positive, or stale rounds.
Chainlink DON → AggregatorV3Interface feed → consumer latestRoundData()
Consumers may wrap the feed behind a local interface; that is optional. Do not assume a project-specific adapter name.
Quick Reference
| Piece | Role |
|---|---|
AggregatorV3Interface |
latestRoundData() + decimals() |
| Round completeness | answeredInRound >= roundId and updatedAt != 0 |
| Price | answer > 0 (feeds are typically signed int256) |
| Freshness | Compare block.timestamp - updatedAt to a max staleness |
| Scale | Normalize feed decimals to the consumer’s scale (often 18) |
| Pair identity | Prefer canonical uppercase symbols (HBAR, USD) if you hash pair keys |
Hedera chain IDs: testnet 296, mainnet 295.
See references/hedera-feeds.md for where to source Hedera feed addresses. See references/examples.md for read and normalize sketches.
Critical: Completeness Then Staleness
Never return a price from a missing or unfinished round. Revert when:
| Condition | Why |
|---|---|
answeredInRound < roundId |
Aggregator has not finished this round |
updatedAt == 0 |
No successful update |
answer <= 0 |
Invalid / non-positive price |
block.timestamp - updatedAt > maxStaleness |
Stale for this consumer |
(uint80 roundId, int256 answer,, uint256 updatedAt, uint80 answeredInRound) =
feed.latestRoundData();
if (answeredInRound < roundId || updatedAt == 0) revert IncompleteRound();
if (answer <= 0) revert InvalidPrice();
if (block.timestamp - updatedAt > maxStaleness) revert StalePrice(updatedAt, maxStaleness);
Critical: Hedera Feeds, Not Ethereum Addresses
Do not copy Ethereum mainnet aggregator addresses onto Hedera. Look up Hedera-specific Data Feed addresses for chain 295 / 296 and re-check docs before mainnet.
Pair maps (if you use them) should be constructor-only unless the project explicitly supports post-deploy updates.
Decimal Normalization
feed.decimals() is often 8. Convert to the scale your app uses before arithmetic:
uint256 price = normalizeToScale(uint256(answer), feed.decimals(), /* target */ 18);
Keep conversion rounding explicit (usually round down). Do not mix raw aggregator units with 18-decimal amounts.
Checklist
When implementing or reviewing Chainlink reads on Hedera:
- Feed address taken from Hedera Data Feeds docs (not Ethereum)
-
latestRoundDatacompleteness checks before usinganswer - Non-positive prices revert
- Staleness bound is enforced
- Decimals normalized to the consumer scale
- Chain ID is
295or296(or the project’s documented Hedera network)
References
- references/examples.md —
latestRoundDataand normalize sketches - references/hedera-feeds.md — where to source Hedera aggregator addresses
- Chainlink Data Feeds
- Hedera price feed addresses