# Due to bit-shifting errors, reserve amounts in the pump will be corrupted, resulting in wrong oracle values

LibBytes16.storeBytes16 dropped the shl(128,...) mask, so odd-length reserve updates overwrite the lower 128 bits of a storage slot with the upper 128 bits, corrupting pump reserves and oracle values.

- Payout: Contest reward
- Severity: medium
- Program: Basin
- Credited: Trust
- Disclosed: 2023-10-05
- Write-up quality: 6/10
- Original: https://github.com/code-423n4/2023-07-basin-findings/issues/259
- Library page: https://bugbountylibrary.com/r/c4%3A2023-07-basin%3AM-03
- Tags: domain:web3 impact:integrity kind:contest platform:code4rena sev:medium tech:evm tech:solidity technique:source-review vuln:accounting-error vuln:oracle-manipulation

**Target:** LibBytes16 storage library / Pump reserve oracle
**Root cause:** storeBytes16 uses `shr(128, sload(...))` without the paired `shl(128, ...)`, so instead of preserving the destination's lower 128 bits it writes the source slot's upper 128 bits into the lower half.
**Steps:**
1. Trigger a reserve update on the Pump via a Well action with an odd reserve count.
2. Reach the `reserves.length & 1 == 1` branch in storeBytes16.
3. Observe `sstore(add(slot, mul(maxI,32)), add(mload(...), shr(128, sload(add(slot, maxI)))))` lacks the `shl(128,...)` mask.
4. Result: SLOT[32*32] becomes UPPER:64 | LOWER:UPPER(SLOT[32*32]) instead of preserving lower 128 bits.
**How found:** Compared the correct LibBytes overwrite pattern `shl(128, shr(128, sload(...)))` against storeBytes16 and noticed the `shl()` was discarded, producing a different storage corruption than the slot-confusion bug in the same line.
**Insight:** When auditing assembly storage helpers, diff each `shr`/`shl` mask pair against the reference implementation; a missing `shl(128,...)` silently swaps which 128-bit half is preserved, corrupting packed slots.
