Summary
readCappedReserves
get reserves logic differs from the function update
set last reserves` logic.
Vulnerability Details
When calling update
function, in order to make sure the Geometric means
are not set to zero, we set the reserve min value to 1.
for (uint256 i; i < numberOfReserves; ++i) {
uint256 _reserve;
_reserve = reserves[i];
pumpState.lastReserves[i] =
@> _capReserve(pumpState.lastReserves[i], (_reserve > 0 ? _reserve : 1).fromUIntToLog2(), capExponent);
pumpState.emaReserves[i] =
pumpState.lastReserves[i].mul((ABDKMathQuad.ONE.sub(alphaN))).add(pumpState.emaReserves[i].mul(alphaN));
pumpState.cumulativeReserves[i] =
pumpState.cumulativeReserves[i].add(pumpState.lastReserves[i].mul(deltaTimestampBytes));
}
Now we look at the function `readCappedReserves``
for (uint256 i; i < numberOfReserves; ++i) {
cappedReserves[i] =
@> _capReserve(lastReserves[i], currentReserves[i].fromUIntToLog2(), capExponent).pow_2ToUInt();
}
when pool reserves are zero, we don't have the logic that makes sure Geometric means
are not zero.
Impact
If we use readCappedReserves
to calculate `Geometric means``, possible get zero data.
Tools Used
manual
Recommendation
make sure the logic readCappedReserves
same as update
for (uint256 i; i < numberOfReserves; ++i) {
cappedReserves[i] =
- _capReserve(lastReserves[i], currentReserves[i].fromUIntToLog2(), capExponent).pow_2ToUInt();
+ _capReserve(lastReserves[i], (currentReserves[i] > 0 ? currentReserves[i] : 1).fromUIntToLog2(), capExponent).pow_2ToUInt();
}