PriceFeed#getSqrtPrice()
incorrectly integrates with the Pyth oracle due to only considering expo == -8
as valid prices
#54
Labels
2 (Med Risk)
Assets not at direct risk, but function/availability of the protocol could be impacted or leak value
bug
Something isn't working
primary issue
Highest quality submission among a set of duplicates
🤖_10_group
AI based duplicate group recommendation
sponsor confirmed
Sponsor agrees this is a problem and intends to fix it (OK to use w/ "disagree with severity")
sufficient quality report
This report is of sufficient quality
unsatisfactory
does not satisfy C4 submission criteria; not eligible for awards
Lines of code
https://github.com/code-423n4/2024-05-predy/blob/a9246db5f874a91fb71c296aac6a66902289306a/src/PriceFeed.sol#L45-L58
Vulnerability details
Proof of Concept
Take a look at https://github.com/code-423n4/2024-05-predy/blob/a9246db5f874a91fb71c296aac6a66902289306a/src/PriceFeed.sol#L45-L58
This function returns the square root of the baseToken price quoted in quoteToken, and this data is queried when checking if the vault is in danger in order to liquidate it, with needing a confirmation via
PositionCalculator.isLiquidatable()
.Problem however is that when getting the basePrice, there is an enforcal that the expo must be
-8
due to therequire(basePrice.expo == -8, "INVALID_EXP");
check, this check however is incorrect and would lead to the protocol to not function properly even when valid prices are available on Pyth, since the check would cause the attempt ongetSqrtPrice()
to revert.The above happens because Pyth stores its price in a structure with price itself (int64) and price exponent (int32). Exponent can be any value and must not be
-8
. For example, price123.4567
will be stored as:price =
1234567
expo =
-4
The converted price should be calculated as
1234567 * 10^-4 = 123.4567
However, using the current implementation of Predy querying the prices it would assume this valid price to be invalid because the
expo
is not-8
.This would lead to a serious problem if the quote price has a different
expo
value or if, for example, the pyth price feed is switched for the same market from 8 decimals precision to 6:Since most Pyth price feeds use negative expo, this is quite a feasible scenario: i.e if some token price falls significantly, it might need better precision and thus the oracle price feed will be switched to a price with a higher precision (expo), leading to all attempts of querying the price from Pyth to revert.
Impact
Valid prices from Pyth would be assumed as invalid, and as such the core logic of getting the square root of the baseToken price quoted in quoteToken via
PriceFeed#getSqrtPrice()
would be broken, which translates to even DOSing valid liquidations from the Liquidation logic and any functionality that requires to get the pricesRecommended Mitigation Steps
Consider not hardcoding the
-8
value as the expo that must be attached to the price returned by Pyth.Assessed type
Oracle
The text was updated successfully, but these errors were encountered: