Open sherlock-admin opened 1 year ago
Escalate for 10 USDC 202 and this aren't duplicates.
202 deals with CompoundProvider's treatment of cToken exchange rate in balanceUnderlying() and calcShares().
This issue is about IdleProvider's balanceUnderlying() and calcShares(). The fact that resulting recommendations look similar is a mere coincidence as Idle and Compound have different mechanics (i.e. both were misunderstood, but separately and in a different way).
Escalate for 10 USDC 202 and this aren't duplicates.
202 deals with CompoundProvider's treatment of cToken exchange rate in balanceUnderlying() and calcShares().
This issue is about IdleProvider's balanceUnderlying() and calcShares(). The fact that resulting recommendations look similar is a mere coincidence as Idle and Compound have different mechanics (i.e. both were misunderstood, but separately and in a different way).
You've created a valid escalation for 10 USDC!
To remove the escalation from consideration: Delete your comment.
You may delete or edit your escalation comment anytime before the 48-hour escalation window closes. After that, the escalation becomes final.
Escalation accepted
Considering this issue separate from #202, although the functions and the mitigation is similar, the underlying calculations are different and need to be addressed separately.
Escalation accepted
Considering this issue separate from #202, although the functions and the mitigation is similar, the underlying calculations are different and need to be addressed separately.
This issue's escalations have been accepted!
Contestants' payouts and scores will be updated according to the changes made on this issue.
Fix looks ok
hyh
high
IdleProvider's balanceUnderlying and calcShares outputs are misscaled by up to 10^12
Summary
balanceUnderlying() returns values scaled with Idle LP token decimals instead of the underlying decimals.
calcShares() returns values scaled with underlying decimals instead of the LP token decimals.
Vulnerability Detail
Core reason is exchangeRate() output is similarly and incorrectly processed in both functions. This results in wrong decimals of the both return values.
Idle LP tokens have 18 decimals, while underlying token decimals can differ: for example, while Idle USDC tokens have 18 decimals, USDC have 6.
Impact
Amount of the underlying held by Idle pool and amount of shares needed for a withdrawal can be misstated by magnitudes wheneven underlying token decimals aren't 18, which can lead to protocol-wide losses.
Specifically for USDC and USDT cases balanceUnderlying() is overstated by
10^12
, while calcShares() is understated by10^12
.Code Snippet
balanceUnderlying() cancels out exchangeRate() decimals with dividing by
10^(Underlying Token Decimals)
, which results in Idle LP token decimals:https://github.com/sherlock-audit/2023-01-derby/blob/main/derby-yield-optimiser/contracts/Providers/IdleProvider.sol#L79-L92
As balance() returns Idle token balance and have Idle LP token decimals of 18:
https://github.com/sherlock-audit/2023-01-derby/blob/main/derby-yield-optimiser/contracts/Providers/IdleProvider.sol#L109-L111
While exchangeRate() is scaled with underlying token decimals:
https://github.com/sherlock-audit/2023-01-derby/blob/main/derby-yield-optimiser/contracts/Providers/IdleProvider.sol#L113-L118
https://github.com/Idle-Labs/idle-contracts/blob/develop/contracts/IdleTokenV3_1.sol#L240-L245
Idle LP token decimals are fixed, while underlying token decimals vary.
For example, while USDC underlying have 6 decimals, it's 18 decimals for Idle USDC:
https://etherscan.io/token/0x5274891bec421b39d23760c04a6755ecb444797c
https://etherscan.io/token/0xcddb1bceb7a1979c6caa0229820707429dd3ec6c
balanceUnderlying() is used in Vault rebalancing:
https://github.com/sherlock-audit/2023-01-derby/blob/main/derby-yield-optimiser/contracts/Vault.sol#L178-L192
https://github.com/sherlock-audit/2023-01-derby/blob/main/derby-yield-optimiser/contracts/Vault.sol#L111-L118
Similarly in calcShares() the
shares
scale is corrected wrongly, resulting with it having underlying decimals instead of LP token decimals (exchangeRate(_cToken)
hasdecimals
scale cancelled by10 ** decimals
,_amount
is in underlying):https://github.com/sherlock-audit/2023-01-derby/blob/main/derby-yield-optimiser/contracts/Providers/IdleProvider.sol#L94-L103
calcShares() is used in rebalancing as well:
https://github.com/sherlock-audit/2023-01-derby/blob/main/derby-yield-optimiser/contracts/Vault.sol#L307-L315
Tool used
Manual Review
Recommendation
Idle exchange rate is specifically scaled so that
LPToken_balance * price
has18 + Underlying Token Decimals
, so it's enough to use1e18
:https://github.com/sherlock-audit/2023-01-derby/blob/main/derby-yield-optimiser/contracts/Providers/IdleProvider.sol#L79-L92
https://github.com/sherlock-audit/2023-01-derby/blob/main/derby-yield-optimiser/contracts/Providers/IdleProvider.sol#L94-L103