Missing checks for stale prices from oracle
Description
An oracle may fail to update and provide the most recent information due to its nature. Therefore, a protocol must verify whether the oracle is supplying outdated information.
Palmy Finance utilizes a price oracle to obtain a price of an asset. The ChainsightOracle contract has the updateState
function, which the oracle provider calls in order to supply the price information:
function updateState(bytes calldata _data) external override {
data[msg.sender] = _data;
emit StateUpdated(msg.sender, _data);
}
Because this function does not store the timestamp of the last update of the state, it is impossible to check if the price information is stale or not.
If the oracle does not receive price information, it fall backs to the fallback oracle. The authorized party can submit the price to the fallback oracle using the submitPrices
function of the PalmyFallbackOracle contract:
function submitPrices(address[] calldata assets, uint128[] calldata prices) external onlySybil {
require(assets.length == prices.length, 'INCONSISTENT_PARAMS_LENGTH');
for (uint256 i = 0; i < assets.length; i++) {
_prices[assets[i]] = Price(uint64(block.number), uint64(block.timestamp), prices[i]);
}
emit PricesSubmitted(msg.sender, assets, prices);
}
This function also does not store the timestamp of the last price, and it is impossible to check the staleness of the price information.
Impact
When the oracle does not operate properly or the authorized party does not update the price on the fallback oracle in a timely manner, an attacker can take an opportunity of arbitrage by exploiting the difference between the stale and true price. This can lead to the loss of funds in the protocol.
Recommendations
Consider storing the timestamp of the price information and checking it when the business logic uses the price information.