Recumbent Daisy Salmon
Medium
All oracle token price timestamp not check it will cause the price is old than the latest price when the oracle is not update on time
In API3Oracle.sol:79
the code read from the api3 oracle, but not check the return timestamp, if the oracle doesn't update on time. It will lead to an old price.
In the function's @notice
it says it will get the latest price from the API3 proxy but not check the timestamp may break it
// API3 returns prices with scaled up by 1e18 base
// https://docs.api3.org/dapps/integration/contract-integration.html#using-value
(int224 price,) = api3Proxy.read(); // <-- Here
Also in PythOracle.sol:98
pyth oracle implement, the code use getPriceUnsafe which may return a very old price. The pyth doucment point out this and recommand to use the getPrice function and check the timestamp and confidence (pyth returns the confidence of the price, it should alse be checked):
The following code use getPriceUnsafe:
function _getLatestPrice(address token) internal view returns (uint256, uint256) {
// Return 0 if price feed id is not set, reverts are handled by caller
if (priceFeedIds[token] == bytes32(0)) return (0, 0);
bytes32 priceFeedId = priceFeedIds[token];
PythStructs.Price memory pythPrice = pyth.getPriceUnsafe(priceFeedId); // <-- Here
uint256 price = uint256(uint64(pythPrice.price));
uint256 expo = uint256(uint32(-pythPrice.expo));
return (price, expo);
}
The oracle's timestamp not validate in Bond oracle. The Bond returns a ReferenceData structure and inside it has a update time:
In BandOracle.sol:85
the code should check the update timestamp to avoid the too old price
function _getLatestPrice(address token) internal view returns (uint256) {
// Return 0 if underlying symbol is not set, reverts are handled by caller
if (bytes(tokenToBandSymbol[token]).length == 0) return 0;
IStdReference.ReferenceData memory data = bandReference.getReferenceData(tokenToBandSymbol[token], QUOTE_SYMBOL); // <-- Here
return data.rate;
}
No response
No response
No response
No response
No response
The code can use the oracle's timestamp to do more check, if the timestamp is much older than now, maybe revert the transaction. The API3 oracle be done use following code to check the timestamp, the pyth and Bond oracle are the same issue.
(int224 price,uint256 timestamp) = api3Proxy.read();
if(block.timestamp - 24 * 60 * 60 > timestamp) { // maybe 24 hours
revert("stale price, more than 24 hours old");
}