# Deny of service in CNote.doTransferOut

CNote.doTransferOut requires the contract's token balance to be exactly zero after transfer, so anyone can send 1 token to brick withdrawals.

- Payout: Contest reward
- Severity: high
- Program: Canto
- Credited: 0x1f8b
- Disclosed: 2022-10-18
- Write-up quality: 6/10
- Original: https://github.com/code-423n4/2022-06-NewBlockchain-v2-findings/issues/43
- Library page: https://bugbountylibrary.com/r/c4%3A2022-06-canto-v2%3AH-02
- Tags: domain:web3 impact:dos kind:contest platform:code4rena sev:high tech:evm tech:solidity technique:source-review vuln:dos

**Target:** CNote.sol doTransferOut in Canto lending market
**Root cause:** doTransferOut asserts token.balanceOf(address(this)) == 0 after transferring the accountant-specified amount, so any residual or rebasing balance makes the check fail and reverts.
**Steps:**
1. Attacker sends 1 underlying token directly to the CNote contract address.
2. Victim calls a CToken function that invokes doTransferOut (e.g. redeem/borrow).
3. doTransferOut transfers `amount`, then `require(token.balanceOf(address(this)) == 0)` fails due to the extra token, reverting the tx.
**How found:** Code review of doTransferOut noticed the strict zero-balance assertion after transfer, and reasoned that any external token transfer or rebasing balance would break it.
**Exploitation:** Anyone can grief by transferring a single underlying token to the CNote contract, permanently breaking doTransferOut and all inherited CToken functions that rely on it until the stray balance is removed.
**Insight:** Strict equality checks on token balances after transfers are griefable: any external deposit or rebasing token breaks them. Look for `balanceOf(...) == 0` post-transfer assertions in lending/redemption paths.
