# transfer_share_and_rewards can be used to transfer out shares without transferring reward debt due to rounding

Rounding down in transfer_share_and_rewards lets a receiver get shares with zero reward debt, enabling repeated double-claiming of already-claimed rewards.

- Payout: Contest reward
- Severity: high
- Program: Acala Network
- Credited: carrotsmuggler
- Disclosed: 2024-05-02
- Write-up quality: 6/10
- Original: https://github.com/code-423n4/2024-03-acala-findings/issues/7
- Library page: https://bugbountylibrary.com/r/c4%3A2024-03-acala%3AH-03
- Tags: domain:web3 impact:funds-loss kind:contest platform:code4rena sev:high tech:solidity technique:source-review vuln:business-logic vuln:precision-loss vuln:reward-distribution

**Target:** Substrate rewards module transfer_share_and_rewards
**Root cause:** move_balance = balance*move_share/share rounds down; when balance*move_share < share it becomes 0, so the receiver's reward debt is never increased while shares are transferred.
**Steps:**
1. Alice holds 1000 shares with reward debt 100 after claiming.
2. Call `transfer_share_and_rewards(ALICE, DOT_POOL, 5, BOB)` so move_share=5, share=1000, balance=100.
3. move_balance = 100*5/1000 = 0, so BOB gets 5 shares with reward debt 0.
4. BOB calls `claim_rewards` and receives rewards already claimed by Alice.
5. Repeat with small fractions to drain the reward pool.
**How found:** Code review of the move_balance formula noticing integer division rounds down to zero for small move_share relative to share.
**Exploitation:** Attacker splits a position into many accounts via tiny share transfers so each receiver has zero reward debt, then each claims rewards already paid out, draining the pool.
**Escalation:** Repeat transfers across many accounts to scale drained rewards.
**Insight:** In share/reward-debt accounting, check integer division that can truncate to zero when splitting positions; tiny-share transfers can zero out debt accounting.
