hats-finance / StakeWise-0xd91cd6ed6c9a112fdc112b1a3c66e47697f522cd

Liquid staking protocol for Ethereum
Other
0 stars 0 forks source link

ChainlinkPriceOracle latestRoundData might return stale or incorrect results #89

Open hats-bug-reporter[bot] opened 1 year ago

hats-bug-reporter[bot] commented 1 year ago

Github username: @Nabeel-javaid Submission hash (on-chain): 0x4f27574e5d5b09674cf8e4867b6f44650ca447dca1fb8aaf8726484cbbb57c79 Severity: medium

Description: Description\ The contract is using chainlink price oracle to fetch the latest price feed but there isn't any kind of check on this.

Attack Scenario\ In the current implementation of PriceFeed.sol, there is no freshness check. This could lead to stale prices being used.

If the market price of the token drops very quickly ("flash crashes"), and Chainlink's feed does not get updated in time, the smart contract will continue to believe the token is worth more than the market value.

Chainlink also advise developers to check for the updatedAt before using the price:

Your application should track the latestTimestamp variable or use the updatedAt value from the latestRoundData() function to make sure that the latest answer is recent enough for your application to use it. If your application detects that the reported answer is not updated within the heartbeat or within time limits that you determine are acceptable for your application, pause operation or switch to an alternate operation mode while identifying the cause of the delay.

And they have this heartbeat concept:

Chainlink Price Feeds do not provide streaming data. Rather, the aggregator updates its latestAnswer when the value deviates beyond a specified threshold or when the heartbeat idle time has passed. You can find the heartbeat and deviation values for each data feed at data.chain.link or in the Contract Addresses lists.

The Heartbeat on Arbitrum is usually 1h.

Source: https://docs.chain.link/docs/arbitrum-price-feed

Recommendation

implements the checks like this

 (uint80 roundId, int256 answer, , uint256 updatedAt, uint80 answeredInRound) = oracle.latestRoundData();

        require(updatedAt > 0, "Round is not complete");
        require(answer >= 0, "Malfunction");
        require(answeredInRound >= roundID, "Stale price");
tsudmi commented 1 year ago

The PriceFeed contract is used to display osETH price in ETH from the protocol perspective. For the secondary market we will create a real chainlink oracle