`LibLastReserveBytes::storeLastReserves` has no check for reserves being too large
After every liquidity event & swap, the IPump::update()is called. To update the pump, theLibLastReserveBytes::storeLastReservesfunction is used. This packs the reserve data intobytes32` slots in storage. A slot is then broken down into the following components:\\n1 byte for reserves array length\\n5 bytes for `timestamp`\\n16 bytes for each reserve balance\\nThis adds to 22 bytes total, but the function also attempts to pack the second reserve balance in the `bytes32` object. This would mean the `bytes32` would need 38 bytes total:\\n`1(length) + 5(timestamp) + 16(reserve balance 1) + 16(reserve balance 2) = 38 bytes`\\nTo fit all this data into the `bytes32`, the function cuts off the last few bytes of the reserve balances using shift, as shown below.\\n```\\nsrc\\libraries\\LibLastReserveBytes.sol\\n   uint8 n = uint8(reserves.length);\\n   if (n == 1) {\\n       assembly {\\n           sstore(slot, or(or(shl(208, lastTimestamp), shl(248, n)), shl(104, shr(152, mload(add(reserves, 32))))))\\n       }\\n       return;\\n   }\\n   assembly {\\n       sstore(\\n           slot,\\n           or(\\n               or(shl(208, lastTimestamp), shl(248, n)),\\n               or(shl(104, shr(152, mload(add(reserves, 32)))), shr(152, mload(add(reserves, 64))))\\n           )\\n       )\\n       // slot := add(slot, 32)\\n   }\\n```\\n\\nSo if the amount being stored is too large, the actual stored value will be different than what was expected to be stored.\\nOn the other hand, the `LibBytes.sol` does seem to have a check:\\n```\\nrequire(reserves[0] <= type(uint128).max, "ByteStorage: too large");\\n```\\n\\nThe `_setReserves` function calls this library after every reserve update in the well. So in practice, with the currently implemented wells & pumps, this check would cause a revert.\\nHowever, a well that is implemented without this check could additionally trigger the pumps to cut off reserve data, meaning prices would be incorrect.
We recommend adding a check on the size of reserves in `LibLastReseveBytes`.\\nAdditionally, it is recommended to add comments to `LibLastReseveBytes` to inform users about the invariants of the system and how the max size of reserves should be equal to the max size of a `bytes16` and not a `uint256`.
While we assume users will be explicitly warned about malicious Wells and are unlikely to interact with invalid Wells, we assess the severity to be MEDIUM.\\nProof of Concept:\\n```\\nfunction testStoreAndReadTwo() public {\\n    uint40 lastTimeStamp = 12345363;\\n    bytes16[] memory reserves = new bytes16[](2);\\n    reserves[0] = 0xffffffffffffffffffffffffffffffff; // This is too big!\\n    reserves[1] = 0x11111111111111111111111100000000;\\n    RESERVES_STORAGE_SLOT.storeLastReserves(lastTimeStamp, reserves);\\n    (\\n        uint8 n,\\n        uint40 _lastTimeStamp,\\n        bytes16[] memory _reserves\\n    ) = RESERVES_STORAGE_SLOT.readLastReserves();\\n    assertEq(2, n);\\n    assertEq(lastTimeStamp, _lastTimeStamp);\\n    assertEq(reserves[0], _reserves[0]); // This will fail\\n    assertEq(reserves[1], _reserves[1]);\\n    assertEq(reserves.length, _reserves.length);\\n}\\n```\\n
```\\nsrc\\libraries\\LibLastReserveBytes.sol\\n   uint8 n = uint8(reserves.length);\\n   if (n == 1) {\\n       assembly {\\n           sstore(slot, or(or(shl(208, lastTimestamp), shl(248, n)), shl(104, shr(152, mload(add(reserves, 32))))))\\n       }\\n       return;\\n   }\\n   assembly {\\n       sstore(\\n           slot,\\n           or(\\n               or(shl(208, lastTimestamp), shl(248, n)),\\n               or(shl(104, shr(152, mload(add(reserves, 32)))), shr(152, mload(add(reserves, 64))))\\n           )\\n       )\\n       // slot := add(slot, 32)\\n   }\\n```\\n