# Truncation exploitation of partial transfer system

LendingLedger.sync_ledger truncates rewardDebt on partial transfers, letting a user repeat tiny deltas to claim unearned CANTO rewards instantly.

- Payout: Contest reward
- Severity: medium
- Program: Canto
- Credited: 0xsomeone
- Disclosed: 2024-04-26
- Write-up quality: 6/10
- Original: https://github.com/code-423n4/2024-03-neobase-findings/issues/15
- Library page: https://bugbountylibrary.com/r/c4%3A2024-03-neobase%3AM-05
- Tags: domain:web3 impact:funds-loss kind:contest platform:code4rena sev:medium tech:solidity technique:race-window technique:source-review vuln:business-logic vuln:precision-loss vuln:reward-distribution

**Target:** LendingLedger::sync_ledger / claim reward accounting
**Root cause:** Partial transfers compute rewardDebt increment as (_delta * accCantoPerShare)/1e18 which truncates to zero for small deltas, while claim uses cumulative user.amount, so repeated tiny transfers accumulate untracked debt.
**Steps:**
1. Deploy LendingLedger test harness and call setupStateBeforeClaim().
2. Advance blocks and call claim(lendingMarket) as lender so accCantoPerShare is not 1e18.
3. Compute remainder = accCantoPerShare % 1e18 and numberOfTimesForWholeValue = 1e18 / remainder.
4. Loop numberOfTimesForWholeValue+1 times: as lendingMarket call `sync_ledger(lender, -1)` then `sync_ledger(noBalanceLender, 1)`.
5. As noBalanceLender call `claim(lendingMarket)`; balance increases despite no prior entitlement.
6. Run `forge test --match-test testFreeRewards -vv` to observe profit != 0.
**How found:** Code reading of sync_ledger's debt update formula spotted integer truncation when delta*accCantoPerShare < 1e18, then reasoned that claim uses cumulative user.amount so repeated truncated deltas sum into a claimable whole.
**Exploitation:** Attacker with a lending position repeatedly performs minimal partial transfers (delta small enough that delta*accCantoPerShare/1e18 truncates to 0) between accounts via the gauge, accumulating user.amount without corresponding rewardDebt, then claims the truncated rewards immediately and compounds by repeating.
**Escalation:** Loop is unbounded and repeatable, compounding extracted rewards; also causes cumulative reward accounting to under-fund the last claimer, making their claim revert.
**Insight:** In reward-debt accounting, check whether the per-transfer debt increment can round to zero while the cumulative balance still grows; test by looping minimal deltas until the truncated remainder sums to 1e18.
