FujiOracle - _getUSDPrice does not detect stale oracle prices; General Oracle Risks
The external Chainlink oracle, which provides index price information to the system, introduces risk inherent to any dependency on third-party data sources. For example, the oracle could fall behind or otherwise fail to be maintained, resulting in outdated data being fed to the index price calculations. Oracle reliance has historically resulted in crippled on-chain systems, and complications that lead to these outcomes can arise from things as simple as network congestion.\\nThis is more extreme in lesser-known tokens with fewer ChainLink Price feeds to update the price frequently.\\nEnsuring that unexpected oracle return values are correctly handled will reduce reliance on off-chain components and increase the resiliency of the smart contract system that depends on them.\\nThe codebase, as is, relies on `chainLinkOracle.latestRoundData()` and does not check the `timestamp` or `answeredIn` round of the returned price.\\nHere's how the oracle is consumed, skipping any fields that would allow checking for stale data:\\n```\\n/\\*\\*\\n \\* @dev Calculates the USD price of asset.\\n \\* @param \\_asset: the asset address.\\n \\* Returns the USD price of the given asset\\n \\*/\\nfunction \\_getUSDPrice(address \\_asset) internal view returns (uint256 price) {\\n require(usdPriceFeeds[\\_asset] != address(0), Errors.ORACLE\\_NONE\\_PRICE\\_FEED);\\n\\n (, int256 latestPrice, , , ) = AggregatorV3Interface(usdPriceFeeds[\\_asset]).latestRoundData();\\n\\n price = uint256(latestPrice);\\n}\\n```\\n\\nHere's the implementation of the v0.6 FluxAggregator Chainlink feed with a note that timestamps should be checked.\\n```\\n\\* @return updatedAt is the timestamp when the round last was updated (i.e.\\n\\* answer was last computed)\\n```\\n
Perform sanity checks on the price returned by the oracle. If the price is older, not within configured limits, revert or handle in other means.\\nThe oracle does not provide any means to remove a potentially broken price-feed (e.g., by updating its address to `address(0)` or by pausing specific feeds or the complete oracle). The only way to pause an oracle right now is to deploy a new oracle contract. Therefore, consider adding minimally invasive functionality to pause the price-feeds if the oracle becomes unreliable.\\nMonitor the oracle data off-chain and intervene if it becomes unreliable.\\nOn-chain, realistically, both `answeredInRound` and `updatedAt` must be checked within acceptable bounds.\\n`answeredInRound == latestRound` - in this case, data may be assumed to be fresh while it might not be because the feed was entirely abandoned by nodes (no one starting a new round). Also, there's a good chance that many feeds won't always be super up-to-date (it might be acceptable to allow a threshold). A strict check might lead to transactions failing (race; e.g., round just timed out).\\n`roundId + threshold >= answeredInRound` - would allow a deviation of threshold rounds. This check alone might still result in stale data to be used if there are no more rounds. Therefore, this should be combined with `updatedAt + threshold >= block.timestamp`.
```\\n/\\*\\*\\n \\* @dev Calculates the USD price of asset.\\n \\* @param \\_asset: the asset address.\\n \\* Returns the USD price of the given asset\\n \\*/\\nfunction \\_getUSDPrice(address \\_asset) internal view returns (uint256 price) {\\n require(usdPriceFeeds[\\_asset] != address(0), Errors.ORACLE\\_NONE\\_PRICE\\_FEED);\\n\\n (, int256 latestPrice, , , ) = AggregatorV3Interface(usdPriceFeeds[\\_asset]).latestRoundData();\\n\\n price = uint256(latestPrice);\\n}\\n```\\n