Summary
The TimeWeightedAverage::calculateAverage function returns an incorrect value when timestamp <= self.startTime after executing the updateValue function. The intended behavior of calculateAverage is to return the original initial value of self.value when the timestamp precedes the start time. However, since the updateValue function modifies self.value, the returned value after an update no longer reflects the original initial value.
Vulnerability Details
function calculateAverage(
Period storage self,
uint256 timestamp
) internal view returns (uint256) {
if (timestamp <= self.startTime) return self.value; <==@found
uint256 endTime = timestamp > self.endTime ? self.endTime : timestamp;
uint256 totalWeightedSum = self.weightedSum;
if (endTime > self.lastUpdateTime) {
uint256 duration = endTime - self.lastUpdateTime;
uint256 timeWeightedValue = self.value * duration;
if (duration > 0 && timeWeightedValue / duration != self.value) revert ValueOverflow();
totalWeightedSum += timeWeightedValue;
}
return totalWeightedSum / (endTime - self.startTime);
}
Impact
the returned value may be incorrect
Tools Used
Recommendations
1.Record the initialValue in createPeriod:
+ uint256 initialValue;
function createPeriod(
Period storage self,
uint256 startTime,
uint256 duration,
uint256 initialValue,
uint256 weight
) internal {
if (self.startTime != 0 && startTime < self.startTime + self.totalDuration) {
revert PeriodNotElapsed();
}
if (duration == 0) revert ZeroDuration();
if (weight == 0) revert ZeroWeight();
self.startTime = startTime;
self.endTime = startTime + duration;
self.lastUpdateTime = startTime;
+ initialValue=initialValue;
self.value = initialValue;
self.weightedSum = 0;
self.totalDuration = duration;
self.weight = weight;
emit PeriodCreated(startTime, duration, initialValue);
}
2.Return initialValue instead of self.value:
function calculateAverage(
Period storage self,
uint256 timestamp
) internal view returns (uint256) {
- if (timestamp <= self.startTime) return self.value;
+ if (timestamp <= self.startTime) return initialValue;
uint256 endTime = timestamp > self.endTime ? self.endTime : timestamp;
uint256 totalWeightedSum = self.weightedSum;
if (endTime > self.lastUpdateTime) {
uint256 duration = endTime - self.lastUpdateTime;
uint256 timeWeightedValue = self.value * duration;
if (duration > 0 && timeWeightedValue / duration != self.value) revert ValueOverflow();
totalWeightedSum += timeWeightedValue;
}
return totalWeightedSum / (endTime - self.startTime);
}