The currentlyAvailable function in Throttle.sol contains a logic error that incorrectly caps the available amount to the hourly limit, even when more than an hour has passed since the last update. This bug prevents the accumulation of unused capacity over extended periods, leading to unintended throttling of actions that should be allowed.
The problematic code is in the currentlyAvailable function:
if (available > limit) available = limit; // This line causes the issue
The last line incorrectly caps the available amount to the hourly limit, regardless of how much time has passed.
Impact
Loss of Accumulated Availability: If more than one hour passes between updates, the system fails to account for the full amount of tokens that should be available. This effectively "loses" the excess accumulation, potentially leading to a significant underestimation of available tokens.
Inconsistent Behavior: The bug creates an inconsistency where frequent updates (less than an hour apart) would allow for more total usage over time compared to infrequent updates. This could lead to unfair advantages for users who interact with the system more frequently.
Operational Inefficiencies: Contracts or users relying on this throttle may experience suboptimal behavior, such as being unable to issue or redeem tokens even when it should be permissible..
Proof of Concept
function currentlyAvailable(Throttle storage throttle, uint256 limit)
internal
view
returns (uint256 available)
{
uint48 delta = uint48(block.timestamp) - throttle.lastTimestamp; // {seconds}
available = throttle.lastAvailable + (limit * delta) / ONE_HOUR;
if (available > limit) available = limit;
}
Scenario Example
Assume the limit is set to 100 tokens/hour.
If 2 hours have passed since lastTimestamp, the correct available amount should be 200 tokens.
However, due to the incorrect capping logic, the available amount will be incorrectly limited to 100 tokens.
Tools Used
Manual code review
Recommended Mitigation Steps
To fix this issue, the capping logic should be removed or adjusted to allow the available amount to correctly reflect the time elapsed. Here’s a recommended change:
function currentlyAvailable(Throttle storage throttle, uint256 limit)
internal
view
returns (uint256 available)
{
uint48 delta = uint48(block.timestamp) - throttle.lastTimestamp; // {seconds}
available = throttle.lastAvailable + (limit * delta) / ONE_HOUR;
// Remove or adjust the capping logic
// Example: Cap only if `amtRate` is zero, or remove if unnecessary
if (throttle.params.amtRate == 0 && available > limit) {
available = limit;
}
}
This ensures that the available amount is proportional to the time elapsed and correctly reflects the intended throttle behavior.
Lines of code
https://github.com/code-423n4/2024-07-reserve/blob/3f133997e186465f4904553b0f8e86ecb7bbacbf/contracts/libraries/Throttle.sol#L69-L74
Vulnerability details
Vulnerability Description
The
currentlyAvailable
function inThrottle.sol
contains a logic error that incorrectly caps the available amount to the hourly limit, even when more than an hour has passed since the last update. This bug prevents the accumulation of unused capacity over extended periods, leading to unintended throttling of actions that should be allowed.The problematic code is in the currentlyAvailable function:
The last line incorrectly caps the available amount to the hourly limit, regardless of how much time has passed.
Impact
Proof of Concept
Scenario Example
Tools Used
Manual code review
Recommended Mitigation Steps
To fix this issue, the capping logic should be removed or adjusted to allow the available amount to correctly reflect the time elapsed. Here’s a recommended change:
This ensures that the available amount is proportional to the time elapsed and correctly reflects the intended throttle behavior.
Assessed type
Other