Core Contracts

Regnum Aurum Acquisition Corp
HardhatReal World AssetsNFT
77,280 USDC
View results
Submission Details
Severity: medium
Invalid

Time-Weighted Average Calculations Incorrect When Querying Historical Averages

Summary

The calculateAverage function in the TimeWeightedAverage library fails to validate that the queried timestamp occurs after the most recent value update (lastUpdateTime). This allows querying historical averages while incorrectly including future updates in the calculation, corrupting time-weighted average.

Vulnerability Details

The vulnerability stems from the calculateAverage function including future updates when calculating historical averages. This violates the fundamental principle of time-weighted average calculations which should only consider values known at the query timestamp.

while current protocol implementations are not directly affected due to strict sequential updates, this vulnerability in the library's core logic poses a significant risk for future protocol components or modifications that might rely on historical average calculations, potentially leading to corrupted time-weighted values and economic exploits.

Impact

This bug affects contracts that will be using TimeWeightedAverage -calculateAverage function. for example:

  • FeeCollector - Incorrect reward distributions

  • GaugeController - Corrupted gauge weights

  • RAAC/RWA Gauges - Invalid emission calculations

POC:

function test_calculateAverage() public{
/*
|-------------|-------------------|----------|
1sec v1 11sec v2 31sec v3 51sec
v1=100,v2=200,v3=300
Timeline: t=1 (100) → t=11 (200) → t=31 (300)
calculateAverage at t=21sec.
average should be = [200*(21-11) + 100*(11-1)]/(21-1) = (2000+1000)/20 =150
*/
//create period
period.createPeriod(block.timestamp, 50, 100, 1e18);
vm.warp(11);
period.updateValue(200,block.timestamp);
assertEq(period.value,200);//test pass
vm.warp(31);
period.updateValue(300,block.timestamp);
assertEq(period.value,300);//test pass
uint avg=period.calculateAverage(21);
console.log("average is ",avg);//avg comes to be 250
assertEq(avg,150);//fails
}

Recommendations

  • Can add timestamp validation and revert for historical queries

++ require( timestamp >= self.lastUpdateTime,
"TWAV: Timestamp precedes last update"
);
  • Or enable historical queries by using a snapshot mechanism to Implement historical tracking for legitimate past queries

    struct Snapshot {
    uint256 timestamp;
    uint256 value;
    }
    Snapshot[] public history;
Updates

Lead Judging Commences

inallhonesty Lead Judge 4 months ago
Submission Judgement Published
Invalidated
Reason: Non-acceptable severity
Assigned finding tags:

TimeWeightedAverage::calculateAverage incorrectly includes future values when querying historical averages, corrupting time-weighted calculations that depend on temporal integrity

inallhonesty Lead Judge 4 months ago
Submission Judgement Published
Invalidated
Reason: Non-acceptable severity
Assigned finding tags:

TimeWeightedAverage::calculateAverage incorrectly includes future values when querying historical averages, corrupting time-weighted calculations that depend on temporal integrity

Support

FAQs

Can't find an answer? Chat with us on Discord, Twitter or Linkedin.