# Due to slot confusion, reserve amounts in the pump will be corrupted, resulting in wrong oracle values

LibLastReserveBytes and LibBytes16 read the wrong storage slot when packing an odd reserve count, corrupting pump reserve data 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/260
- Library page: https://bugbountylibrary.com/r/c4%3A2023-07-basin%3AM-02
- Tags: domain:web3 impact:integrity kind:contest platform:code4rena sev:medium tech:evm tech:solidity technique:source-review vuln:accounting-error

**Target:** MultiFlowPump reserve storage libraries (LibBytes16, LibLastReserveBytes)
**Root cause:** When reserves.length is odd, the code reads the previous half-slot via `sload(add(slot, maxI))` instead of `sload(add(slot, mul(maxI, 32)))`, so the upper 128 bits come from a reserve at a much lower index and get written into the wrong slot.
**Steps:**
1. Trigger a reserve update on the pump via a Well action with an odd reserve count.
2. Use reserves array `[0,1,2,...,63,64]` so maxI=32.
3. storeLastReserves executes `sstore(add(slot, mul(maxI,32)), add(mload(...), shr(128, shl(128, sload(add(slot, maxI))))))`.
4. Observe SLOT[32*32] = UPPER: 64 | LOWER: SLOT[32] = 64 | 3, corrupting the 64th reserve with the 4th reserve's value.
**How found:** Code-reading comparison of LibBytes (correct) against LibBytes16/LibLastReserveBytes (incorrect): noticed the odd-length branch in the latter two omits `mul(maxI, 32)` when computing the sload offset, then substituted maxI=32 to show the first real corruption.
**Insight:** When auditing packed-storage libraries, diff sibling implementations of the same packing logic; an omitted `mul(slotSize)` in one variant's sload offset silently aliases a lower-index slot once the index exceeds 31.
