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);
}