Summary
The accounts storage variable in the PriorityPool contract can grow indefinitely, leading to potential node timeouts when accessing data via the getAccounts and getAccountData functions.
Vulnerability Details
As the accounts array expands without limit, applications using node service providers like Alchemy or Infura may face timeouts during data retrieval. While these functions are view functions and don’t incur gas costs, the increasing computational complexity can make requests too burdensome, resulting in some node providers timing out. Consequently, applications might be forced to deploy their own nodes to retrieve necessary data, complicating integration and user experience.
Furthermore, if other contracts interact with the PriorityPool, they risk encountering out-of-gas errors during internal transactions. This limitation could impede integration efforts, making it more challenging for developers to build efficient applications that rely on the PriorityPool.
function _deposit(
address _account,
uint256 _amount,
bool _shouldQueue,
bytes[] memory _data
) internal {
if (poolStatus != PoolStatus.OPEN) revert DepositsDisabled();
uint256 toDeposit = _amount;
if (totalQueued == 0) {
uint256 queuedWithdrawals = withdrawalPool.getTotalQueuedWithdrawals();
if (queuedWithdrawals != 0) {
uint256 toDepositIntoQueue = toDeposit <= queuedWithdrawals
? toDeposit
: queuedWithdrawals;
withdrawalPool.deposit(toDepositIntoQueue);
toDeposit -= toDepositIntoQueue;
IERC20Upgradeable(address(stakingPool)).safeTransfer(_account, toDepositIntoQueue);
}
if (toDeposit != 0) {
uint256 canDeposit = stakingPool.canDeposit();
if (canDeposit != 0) {
uint256 toDepositIntoPool = toDeposit <= canDeposit ? toDeposit : canDeposit;
stakingPool.deposit(_account, toDepositIntoPool, _data);
toDeposit -= toDepositIntoPool;
}
}
}
if (toDeposit != 0) {
if (_shouldQueue) {
_requireNotPaused();
if (accountIndexes[_account] == 0) {
@> inserting a new element for each new account that deposits into the PriorityPool
@> even if the account deposits 1 wei
accounts.push(_account);
accountIndexes[_account] = accounts.length - 1;
}
accountQueuedTokens[_account] += toDeposit;
totalQueued += toDeposit;
} else {
token.safeTransfer(_account, toDeposit);
}
}
emit Deposit(_account, _amount - toDeposit, _shouldQueue ? toDeposit : 0);
}
function getAccounts() external view returns (address[] memory) {
return accounts;
}
function getAccountData()
external
view
returns (address[] memory, uint256[] memory, uint256[] memory)
{
uint256[] memory reSDLBalances = new uint256[]();
uint256[] memory queuedBalances = new uint256[]();
for (uint256 i = 0; i < reSDLBalances.length; ++i) {
address account = accounts[i];
reSDLBalances[i] = sdlPool.effectiveBalanceOf(account);
queuedBalances[i] = accountQueuedTokens[account];
}
return (accounts, reSDLBalances, queuedBalances);
}
Impact
Potential timeouts in node providers when fetching data from the getAccounts and getAccountData functions. Additionally, contracts interacting with these functions may struggle to integrate due to excessive gas consumption.
Tools Used
Manual review.
Recommendations
Use pagination to query data. See:
https://programtheblockchain.com/posts/2018/04/20/storage-patterns-pagination/