ChainlinkPriceOracle fetches prices from the Chainlink contracts. But the price feeds in the consideration has a very long price heartbeat and deviation rate which might lead to wrong price calculation and loss of token to the user.
According to the chainlink docs, following are the Price feeds info for the assets that will be used initially:
Feed | Heartbeat | Deviation | Docs link |
---|---|---|---|
RETH / ETH | 2% | 86400s | Docs |
CBETH / ETH | 1% | 86400s | Docs |
RETH / ETH | 0.5% | 86400s | Docs |
For Info, Heartbeat and Deviation are variables on which the update of the prices for price feeds depends. That mean the current price feed price will be updated for the token only if one of them is met. That means if we take the example of RETH here, the price feed will be update only when the market price for the RETH fluctuates by 2% or time equal to 86400s(1 day) has passed since last price update. This could be a very problematic thing. Letβs assume a following scenario:
-> Letβs say price feeds was updated at time T1 and price for RETH / ETH is [1]. And since then 43200s(half day) has passed and price has become [1.018] (up by 1.8 %).
-> Now Bob comes and decides to deposit 50 RETH by calling LSTDepositPool::depositAsset(β¦).
-> But the amount of RSETH token he will get is equal to:
depositAmount = 500 RETH
// balances
bob = 500 RETH
LRTDepositPool = 0
EigenStrategy = 0
NodeDelegator = 0
// RETH Price
RETHPrice = 1e18 // hasn't updated because heartbeat and deviation hasn't reached
// total ETH (assuming zero for the sake of simplicity)
totalETHInPool = 0
RSETHSupply = 0
///////////////////////////////////////////////////////////////
// functions calculations according to chainlink price feeds //
///////////////////////////////////////////////////////////////
rsETHPrice(...) = if ->
(supply = 0) 1 ETH // this condition will met
else ->
totalETHInPool / rsETHTotalSupply
rsEthAmountToMint(...) = depositAmount * RETHPrice / rsETHPrice()
= 500 * 1e18 / 1e18 = 500 rsETH
/////////////////////////////////////////////////////////
/// functions calculations according to market price ////
/////////////////////////////////////////////////////////
rsETHPrice(...) = if ->
(supply = 0) 1 ETH // this condition will met
else ->
totalETHInPool / rsETHTotalSupply
rsEthAmountToMint(...) = depositAmount * RETHPrice / rsETHPrice()
= 500 * (1.018 * 1e18) / 1e18 = ~509 rsETH
As you can see according to the market price, 9 rsETH should be minted extra to the user. But it will not happen as the price feed deviation and heartbeat threshold hasnβt passed. And that is why the prices will not be updated. Even if the checks are added in the future for staleness of price, this mechanism will not let anybody deposit token for a whole day because of staleness checks like maxTimestamp etc.
This is one of the valid issue founded in a sherlock audit. Here is a link: Link
Calculation and Link given in the above section.
It is recommended to use price feeds with less heartbeat and deviation rate. Although the deviation can be handled the heartbeat is still a thing that needs to be considered. Since the time of writing this, Chainlink only support few price feeds for the above tokens with high heartbeat and deviation rate. It is recommended to go for other price oracles or combine more than one together to get the average price.
Oracle
The text was updated successfully, but these errors were encountered:
All reactions