# Owner cannot withdraw all interest due to wrong calculation of accrued interest in WithdrawCarry

WithdrawCarry hardcodes cNOTE exchangeRate scale as 1e28, but cNOTE uses 1e18, so maximumWithdrawable is ~1e-10 of real interest, blocking owner withdrawals.

- Payout: Contest reward
- Severity: high
- Program: Canto
- Credited: 100su
- Disclosed: 2023-12-15
- Write-up quality: 6/10
- Original: https://github.com/code-423n4/2023-11-canto-findings/issues/181
- Library page: https://bugbountylibrary.com/r/c4%3A2023-11-canto%3AH-01
- Tags: domain:web3 impact:funds-loss kind:contest platform:code4rena sev:high tech:evm tech:solidity technique:source-review vuln:business-logic vuln:precision-loss

**Target:** asD WithdrawCarry contract / cNOTE Compound cToken
**Root cause:** maximumWithdrawable divides balance*exchangeRate by 1e28, assuming cNOTE exchangeRate is scaled 1e28, but cNOTE (8 decimals) uses 1e18 scaling, underestimating accrued interest by 1e10.
**Steps:**
1. Read withdrawCarry: `maximumWithdrawable = (cNote.balanceOf(this) * exchangeRateCurrent()) / 1e28 - totalSupply()`
2. Verify cNOTE exchangeRateStored on-chain (~1.00416e18) confirming 1e18 scale, not 1e28
3. Call withdrawCarry with non-zero _amount; require(_amount <= maximumWithdrawable) reverts 'Too many tokens requested' since max is ~1e-10 of true interest
4. Fix: divide by 1e18 or use `balanceOfUnderlying(address(this)) - totalSupply()`
**How found:** Noticed the code comment assumes exchangeRate scaled by 1e28 (standard for 18-decimal cTokens), then verified on-chain that cNOTE has 8 decimals and exchangeRateStored ~1e18, confirming the scale mismatch.
**Insight:** Compound cToken exchangeRate scale depends on underlying decimals (1e(18+underlyingDecimals-8)); cNOTE's 8 decimals yields 1e18, not the usual 1e28 — always verify token decimals on-chain rather than trusting the standard formula.
