sherlock-audit / 2023-07-blueberry-judging

2 stars 1 forks source link

Kow - CurveTricryptoOracle.sol reports heavily undervalued price of tricrypto LP token allowing unsafe position sizes #115

Closed sherlock-admin2 closed 1 year ago

sherlock-admin2 commented 1 year ago

Kow

high

CurveTricryptoOracle.sol reports heavily undervalued price of tricrypto LP token allowing unsafe position sizes

Summary

The getPrice function in CurveTricryptoOracle.sol calculates the price of the tricrypto LP token in ETH rather than USD resulting in extremely undervalued prices reported in the protocol’s context.

Vulnerability Detail

The getPrice function of all oracles in the protocol is supposed to return prices in USD with 18 decimals of precision. This assumption is held when any other contract calls getPrice from an oracle (ie. when validating the position size) .

The CurveTricryptoOracle getPrice function calculates the lp price of a Curve tricrypto lp token using the internal function lpPrice with prices for each of the three tokens in the pool obtained using base.getPrice() (which, from the test and deployment scripts, can be deduced to be obtained from Chainlink USD price feeds for each token processed by the protocol’s Chainlink oracle contracts and reported in USD with 18 decimals). The result of lpPrice is the price of the given tricrypto LP token in USD with 18 decimals (can be verified by manual calculation compared to Curve's pricing and comparison to similar equations used by Yearn and Curve). The issue is this price is then further divided by ethPrice (after scaling by 18 decimals) which is the price of ETH in USD, and then returns the result of this calculation. Consequently, the price reported is in ETH rather than USD, breaking the assumption held when interacting with the oracle.

As a result, since the price is interpreted as a USD price, the price of Curve tricrypto LP tokens will be extremely undervalued (considering the USD price of WETH is approx 1850 USD as of time of writing). Since LP prices are not determined through aggregated sources (as seen in the project's readme), CurveTricryptoOracle will be the source of truth for tricrypto LP tokens, which will be extremely undervalued in the protocol’s contracts.

This is significant when validating the position size to be within a strategy’s parameters that involves the tricrypto pool (which seems to be yet to be implemented from the comments). The added position size is calculated by multiplying the reported LP price with the LP balance of the Spell contract, so it will be severely underestimated allowing users to open and manage positions collectively far greater than permissible by the strategy’s parameters (maxPositionSize which is denominated in USD) - (specifically, the last user can overstep the maxPositionSize since the calculation of the previous position size is not affected) . This is very dangerous as the protocol, and consequently its users, can be silently exposed to additional, unaccounted for risk. (otherwise, opening positions may revert for valid amounts due to undervalued positions falling beneath the minPositionSize)

Impact

Unexpected additional risk past permissible bounds set by strategies employing Curve tricrypto pools due to extremely undervalued reporting of LP token price and consequently dangerous position size leading to high potential loss of funds for users.

Code Snippet

https://github.com/sherlock-audit/2023-07-blueberry/blob/7c7e1c4a8f3012d1afd2e598b656010bb9127836/blueberry-core/contracts/spell/BasicSpell.sol#L39-L47 https://github.com/sherlock-audit/2023-07-blueberry/blob/7c7e1c4a8f3012d1afd2e598b656010bb9127836/blueberry-core/contracts/oracle/CurveTricryptoOracle.sol#L48-L65 https://github.com/sherlock-audit/2023-07-blueberry/blob/7c7e1c4a8f3012d1afd2e598b656010bb9127836/blueberry-core/contracts/oracle/ChainlinkAdapterOracle.sol#L98-L127 https://github.com/sherlock-audit/2023-07-blueberry/blob/7c7e1c4a8f3012d1afd2e598b656010bb9127836/blueberry-core/contracts/spell/BasicSpell.sol#L273-L300

Tool used

Manual Review

Recommendation

Consider directly returning the lpPrice result (ie. without * 1e18 / ethPrice). Additionally, consider using Curve's LP price calculation formula (with div by 1e18 instead of 1e24) to get the price of the LP token in terms of the 0th token (ie. USDT) and multiplying this by the USD price of USDT (then scaling to 1e18) to get the LP price in USD. Manual testing with Chainlink prices comparing both expressions suggested the formula used here differs by up to 1 USD from Curve's LP price formula (after conversion to USD).

Duplicate of #100

sherlock-admin2 commented 1 year ago

1 comment(s) were left on this issue during the judging contest.

0xyPhilic commented:

invalid because the returned value from the lpPrice is in ETHUSD so dividing by ETHUSD returns us the final value in USD