DeFiFoundry
60,000 USDC
View results
Submission Details
Severity: medium
Valid

`MarketConfiguration.update()` doesn't set priceFeedHeartbeatSeconds

Summary

MarketConfiguration.update() simply forgets to set the value priceFeedHeartbeatSeconds to storage.

Vulnerability Details

Here you can see it fetches value from configuration and uses Chainlink:

function getIndexPrice(Data storage self) internal view returns (UD60x18 indexPrice) {
...
@> uint32 priceFeedHeartbeatSeconds = self.configuration.priceFeedHeartbeatSeconds;
...
@> indexPrice = ChainlinkUtil.getPrice(
IAggregatorV3(priceAdapter), priceFeedHeartbeatSeconds, IAggregatorV3(sequencerUptimeFeed)
);
}

And here it reverts:
https://github.com/Cyfrin/2024-07-zaros/blob/d687fe96bb7ace8652778797052a38763fbcbb1b/src/external/chainlink/ChainlinkUtil.sol#L60-L62

try priceFeed.latestRoundData() returns (uint80, int256 answer, uint256, uint256 updatedAt, uint80) {
if (block.timestamp - updatedAt > priceFeedHeartbeatSeconds) {
revert Errors.OraclePriceFeedHeartbeat(address(priceFeed));
}

priceFeedHeartbeatSeconds can't be set to config, so function PerpMarket.getIndexPrice() will always revert.

Impact

PerpMarket.getIndexPrice() always reverts due to stale price. It doesn't revert only in one case when price update was filled in the current block when tx is being executed.

So most of the time protocol can't operate due to that revert because this function is used in core: createOrder, fillOrders, liquidate.

Tools Used

Manual Review

Recommendations

Set:

function update(Data storage self, Data memory params) internal {
...
self.orderFees = params.orderFees;
+ self.priceFeedHeartbeatSeconds = params.priceFeedHeartbeatSeconds;
}
Updates

Lead Judging Commences

inallhonesty Lead Judge about 1 year ago
Submission Judgement Published
Validated
Assigned finding tags:

`MarketConfiguration::update` function lacks `priceFeedHeartbeatSeconds` argument

Support

FAQs

Can't find an answer? Chat with us on Discord, Twitter or Linkedin.