Reserves are bytes16 values that are updated along with timestamp and number of reserve values by a user through the MultiflowPump.update
. The method of storing uses a truncation method to fit multiple bytes16 values into a single slot. This works by truncating the last 3 bytes to bytes13 values which are then stored in the reserve slot.
function storeLastReserves(bytes32 slot, uint40 lastTimestamp, bytes16[] memory reserves) internal {
uint8 n = uint8(reserves.length);
if (n == 1) {
assembly {
sstore(slot, or(or(shl(208, lastTimestamp), shl(248, n)), shl(104, shr(152, mload(add(reserves, 32))))))
}
return;
}
This value can be retrieved through `LibLastReserveBytes.readLastReserveBytes` and is used by functions in the multiflow pump. The issue is the original truncation is not handled during retrieval causing different values than what was initially stored to be retrieved. Most times, this value is alot smaller than what was originally stored by user.
## Impact
Due to improper handling of the original truncation of the reserve values, different values than what was original stored by the original user would lead to issues such as loss of funds and incorrect accounting.
## Proof of Code
1. Insert into `LibLastReserveBytes.t.sol`
function testAuditStoreLastReserveByte() public {
uint40 lastTimestamp = uint40(block.timestamp);
bytes16[] memory reserves = new bytes16[](1);
reserves[0] = 0xffffffffffffffffffffffffffffffff;
RESERVES_STORAGE_SLOT.storeLastReserves(lastTimestamp, reserves);
(uint8 n, uint40 timestamp, bytes16[] memory reserveRes) = RESERVES_STORAGE_SLOT.readLastReserves();
for(uint256 i; i<=reserves.length; ++i) {
assertEq(reserves[i], reserveRes[i]);
}
}
The assertion fails showing that what was originally stored is different from what was retrieved.
## Tools Used
Manual Review
## Recommendations
Account for the original truncation of the bytes16 reserve values to bytes13. During retrieval this value should be corrected to original value stored