Platform: Code4rena
Start Date: 13/11/2023
Pot Size: $24,500 USDC
Total HM: 3
Participants: 120
Period: 4 days
Judge: 0xTheC0der
Id: 306
League: ETH
Rank: 18/120
Findings: 1
Award: $690.37
🌟 Selected for report: 0
🚀 Solo Findings: 0
690.3741 USDC - $690.37
The Compound protocol's CTokens have 8 decimal places, but the team mistakenly believed that cNote also had only 8 decimal places. However, it was discovered that cNote actually has 18 decimal places. This discrepancy caused the withdrawCarry()
function to always revert.
/// @notice Withdraw the interest that accrued, only callable by the owner. /// @param _amount Amount of NOTE to withdraw. 0 for withdrawing the maximum possible amount /// @dev The function checks that the owner does not withdraw too much NOTE, i.e. that a 1:1 NOTE:asD exchange rate can be maintained after the withdrawal function withdrawCarry(uint256 _amount) external onlyOwner { //@audit The exchange rate is scaled by 10^18, not 10^28. uint256 exchangeRate = CTokenInterface(cNote).exchangeRateCurrent(); // Scaled by 1 * 10^(18 - 8 + Underlying Token Decimals), i.e. 10^(28) in our case //@audit `(CTokenInterface(cNote).balanceOf(address(this)) * exchangeRate) / 1e28` => This expression has only 8 decimal places. //@audit `totalSupply()` has 18 decimal places //@audit underflow => always revert uint256 maximumWithdrawable = (CTokenInterface(cNote).balanceOf(address(this)) * exchangeRate) / 1e28 - totalSupply(); //...... //..... }
We can check the decimal places of cNote on Canto Blockchain Explorer.
Read Contract
decimals
To further confirm, we can directly check the exchange rate of cNote.
Read Contract
exchangRateCurrent
Query
VS Code
- uint256 maximumWithdrawable = (CTokenInterface(cNote).balanceOf(address(this)) * exchangeRate) / 1e28 - totalSupply(); + uint256 maximumWithdrawable = (CTokenInterface(cNote).balanceOf(address(this)) * exchangeRate) / 1e18 - totalSupply();
Decimal
#0 - c4-pre-sort
2023-11-18T08:57:54Z
minhquanym marked the issue as duplicate of #227
#1 - c4-judge
2023-11-28T22:57:41Z
MarioPoneder marked the issue as satisfactory