Open sherlock-admin opened 1 year ago
duplicate with #132
Escalate for 10 USDC The only valid duplicate of 202 looks to be 329, all the others are different issues.
Escalate for 10 USDC The only valid duplicate of 202 looks to be 329, all the others are different issues.
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
The only valid duplicate is #329
Escalation accepted
The only valid duplicate is #329
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
CompoundProvider's balanceUnderlying and calcShares outputs are scaled incorrectly
Summary
balanceUnderlying() returns values scaled with CToken decimals instead of the underlying decimals.
calcShares() also incorrectly scales its output, which have underlying decimals instead of the CToken decimals.
Vulnerability Detail
Underlying reason is exchangeRate() output is similarly and incorrectly processed in both functions. This results in wrong decimals of the both return values.
CToken and underlying decimals can differ, for example cDAI has 8 decimals, while DAI has 18.
Impact
Amount of the underlying held by Compound pool and amount of shares needed are misstated by magnitudes, which can lead to protocol-wide losses.
Code Snippet
balanceUnderlying() cancels out exchangeRate() decimals with dividing by
10^(18 - 8 + Underlying Token Decimals)
, which results in CToken decimals:https://github.com/sherlock-audit/2023-01-derby/blob/main/derby-yield-optimiser/contracts/Providers/CompoundProvider.sol#L86-L100
As balance() returns CToken balance and have CToken decimals:
https://github.com/sherlock-audit/2023-01-derby/blob/main/derby-yield-optimiser/contracts/Providers/CompoundProvider.sol#L113-L120
While exchangeRate() is CToken's exchangeRateStored() with (18 - 8 + Underlying Token Decimals) decimals:
https://github.com/sherlock-audit/2023-01-derby/blob/main/derby-yield-optimiser/contracts/Providers/CompoundProvider.sol#L122-L129
https://docs.compound.finance/v2/ctokens/#exchange-rate
So balanceUnderlying() have CTokens decimals, which differ from underlying decimals, for example cUSDC have decimals of 8:
https://etherscan.io/token/0x39aa39c021dfbae8fac545936693ac917d5e7563
While USDC have decimals of 6:
https://etherscan.io/token/0xa0b86991c6218b36c1d19d4a2e9eb0ce3606eb48
cDAI has 8 decimals:
https://etherscan.io/token/0x5d3a536e4d6dbd6114cc1ead35777bab948e3643
DAI has 18:
https://etherscan.io/token/0x6b175474e89094c44da98b954eedeac495271d0f
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
Same for calcShares(), where
shares
scale is corrected wrongly, it has underlying decimals instead of CToken decimals:https://github.com/sherlock-audit/2023-01-derby/blob/main/derby-yield-optimiser/contracts/Providers/CompoundProvider.sol#L107-L111
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
Compound exchange rate is specifically scaled so that
CToken_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/CompoundProvider.sol#L86-L100
https://github.com/sherlock-audit/2023-01-derby/blob/main/derby-yield-optimiser/contracts/Providers/CompoundProvider.sol#L102-L111