# Transfer of Vault tokens can cause accounting errors in other contracts

Vault._transfer downcasts uint256 shares to uint96 while TwabController stores uint112 balances, silently underflowing and letting a depositor double-spend shares in integrating contracts.

- Payout: Contest reward
- Severity: medium
- Program: PoolTogether
- Credited: shaka
- Disclosed: 2023-09-27
- Write-up quality: 6/10
- Original: https://github.com/code-423n4/2023-07-pooltogether-findings/issues/91
- Library page: https://bugbountylibrary.com/r/c4%3A2023-07-pooltogether%3AM-26
- Tags: domain:web3 impact:funds-loss kind:contest platform:code4rena sev:medium tech:solidity technique:source-review vuln:accounting-error vuln:precision-loss

**Target:** Vault.sol _transfer / TwabLib AccountDetails balance
**Root cause:** Vault::_transfer casts _shares to uint96 before calling TwabController, but TwabController stores balances as uint112, so a transfer larger than uint96 max wraps silently instead of reverting.
**Steps:**
1. Deposit `type(uint96).max` twice so vault.balanceOf(alice) = 2*uint96.max
2. Alice approves an integrating contract for all shares
3. Contract calls `vault.transferFrom(alice, address(this), aliceBalance)` and records aliceBalance in a mapping
4. Only uint96.max shares actually move due to silent underflow, but the full 2*uint96.max is recorded
5. Alice still holds uint96.max shares and transfers them to bob, double-spending
**How found:** Code-reading: noticed NatSpec claims uint96 storage but TwabLib.AccountDetails actually uses uint112, making the uint96 downcast in _transfer unsafe.
**Exploitation:** A depositor with balance exceeding uint96 max transfers to an integrating contract that trusts balanceOf; the downcast underflows so fewer shares move than recorded, leaving the depositor able to move the remainder again.
**Insight:** When a contract downcasts to a narrower type than the storage it writes to, check the actual struct field width in the storage library rather than trusting NatSpec comments; mismatched widths create silent truncation.
