Canto Application Specific Dollars and Bonding Curves for 1155s - Soul22's results

Tokenizable bonding curves using a Stablecoin-as-a-Service token

General Information

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

Canto

Findings Distribution

Researcher Performance

Rank: 18/120

Findings: 1

Award: $690.37

🌟 Selected for report: 0

🚀 Solo Findings: 0

Findings Information

Awards

690.3741 USDC - $690.37

Labels

bug
3 (High Risk)
satisfactory
edited-by-warden
duplicate-181

External Links

Lines of code

https://github.com/code-423n4/2023-11-canto/blob/335930cd53cf9a137504a57f1215be52c6d67cb3/asD/src/asD.sol#L73

Vulnerability details

Impact

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.

Proof of Concept

    /// @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.

  1. Click this link
  2. Click Read Contract
  3. Click decimals
  4. The value returned is 18.

To further confirm, we can directly check the exchange rate of cNote.

  1. Click the link provided above.
  2. Click Read Contract
  3. Click exchangRateCurrent
  4. Click Query
  5. The value returned at the time of writing is 1004205695942061800, scaled by 18 decimal places.

Tools Used

VS Code

-         uint256 maximumWithdrawable = (CTokenInterface(cNote).balanceOf(address(this)) * exchangeRate) / 1e28 - totalSupply();

+         uint256 maximumWithdrawable = (CTokenInterface(cNote).balanceOf(address(this)) * exchangeRate) / 1e18 - totalSupply();

Assessed type

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

AuditHub

A portfolio for auditors, a security profile for protocols, a hub for web3 security.

Built bymalatrax © 2024

Auditors

Browse

Contests

Browse

Get in touch

ContactTwitter