This repository has been archived by the owner on Feb 18, 2024. It is now read-only.
_recordPrice()
function incorrectly treats expo
(exponent) from PythStructs.Price
which can lead to protocol malfunction and loss of funds after oracle switch
#45
panprog
medium
PythOracle
_recordPrice()
function incorrectly treatsexpo
(exponent) fromPythStructs.Price
which can lead to protocol malfunction and loss of funds after oracle switchSummary
When pyth price is recorded in PythOracle, it converts price provided by pyth to Fixed6 format. However, it treats
expo
incorrectly: multiplying price by 10 power absolute value ofexpo
:For negative
expo
, price will be incorrect. Moreover, if oracle price is changed to a different number of digits, resulting final price will unexpectedly increase or decrease orders of magnitude from pre-switch price, creating huge unexpected funds loss for many users of the protocol.Vulnerability Detail
Pyth stores its price in a structure with price itself (int64) and price exponent (int32). Exponent can be both positive and negative. For example, price 123.4567 will be stored as:
price
= 1234567expo
= -4The converted price should be calculated as
1234567 * 10^-4 = 123.4567
Large prices can be stored with positive exponent, for example price 12345670000 can be stored as
price
= 1234567expo
= 4However, in both cases PythOracle will convert the price to
Fixed6(1234567) * Fixed6(10^4) = Fixed6(12345670000)
This can lead to a serious problem if, for example, pyth price feed is switched for the same market from 4 decimals precision to 5:
price
: 1234567,expo
: -4), converted by PythOracle toFixed6(12345670000)
price
: 12345670,expo
: -5), converted by PythOracle toFixed6(123456700000)
(10 times the price of feed1)Since most Pyth price feeds use negative
expo
, this is quite feasible scenario: 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, which will make the price unexpectedly grow by orders of magnitude, leading to a chaos and loss of funds for many protocol users due to sudden price jump.Impact
Incorrect oracle price for negative
expo
pyth price feeds which can lead to chaos and loss of funds if price feed is switched to a different-precision feed for the same price.Code Snippet
https://github.com/sherlock-audit/2023-07-perennial/blob/main/perennial-v2/packages/perennial-oracle/contracts/pyth/PythOracle.sol#L202-L203
Tool used
Manual Review
Recommendation
Check the sign of
expo
in pyth price and divide by10**-expo
if it's negative. However, since price is Fixed6 (just 6 decimals), this might lose precision for very small prices (ifexpo
is less than -6), maybe consider switching to Fixed18 or handle it in some other way.Duplicate of #56
The text was updated successfully, but these errors were encountered: