Liquid Staking

Stakelink
DeFiHardhatOracle
50,000 USDC
View results
Submission Details
Severity: low
Invalid

Out-of-Bounds Error in `OperatorVC::updateDeposits` Reverts Under Certain Accounting States

Summary

The OperatorVC::updateDeposits function can revert with an out-of-bounds error when rewards fall below the _minRewards threshold. This issue occurs under specific accounting states, where the function creates an array of size 1 but attempts to access larger indices in a subsequent loop. As a result, the deposit accounting and distribution of fees and rewards to network actors can be disrupted.

Vulnerability Details

The OperatorVault::updateDeposits function calculates depositChange based on the total deposits and rewards:

uint256 principal = getPrincipalDeposits();
uint256 rewards = getRewards();
uint256 totalDeposits = principal + rewards;
int256 depositChange = int256(totalDeposits) - int256(uint256(trackedTotalDeposits));

If the rewards are below the _minRewards threshold, they are not sent to the contract, which can result in the condition where depositChange <= 0 but operatorRewards != 0. This creates an issue where the length of the receivers and amounts arrays is 1, but the function attempts to access out-of-bounds indices in the subsequent loop.

In OperatorVCS::updateDeposits, this error occurs when the function iterates through multiple vaults, calling updateDeposits for each vault:

for (uint256 i = 0; i < vaultCount; ++i) {
(uint256 deposits, uint256 principal, uint256 rewards) =
IOperatorVault(address(vaults[i])).updateDeposits(_minRewards, _rewardsReceiver);
vaultDeposits += deposits;
newTotalPrincipalDeposits += principal;
operatorRewards += rewards;
}

When the following else block is executed in the StakingPool::_updateStrategyRewards function, it assumes that the receivers and amounts arrays are larger than 1, leading to a potential out-of-bounds error:

} else {
for (uint256 i = 1; i < receivers.length; ++i) {
receivers[i] = fees[i - 1].receiver;
amounts[i] = (uint256(depositChange) * fees[i - 1].basisPoints) / 10000;
}
}

This occurs because the loop starts at index 1, but the array might only have a length of 1, causing the function to attempt to access an invalid index.

Impact

This bug can prevent the smooth update of deposit accounting and the distribution of fees and rewards to network participants. If the function reverts, it may disrupt the protocol's ability to process reward claims, leading to operational issues.

Tools Used

Manual

Recommendations

Ensure that the receivers and amounts arrays are appropriately sized before entering the loop in the else block. Additionally, add a check to prevent accessing out-of-bounds indices in the for loop when the arrays contain fewer than the expected number of elements. This will prevent reverts and ensure smooth operation during reward and fee distribution.

Updates

Lead Judging Commences

inallhonesty Lead Judge
10 months ago
inallhonesty Lead Judge 10 months ago
Submission Judgement Published
Invalidated
Reason: Incorrect statement

Support

FAQs

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