Liquid Staking

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

In Some circumstances, `PriorityPool::_deposit` will always revert due to missing approval

Summary

In PriorityPool::_deposit there is a missing approval to withdrawalPool that causes any call to deposit() to fail when the condition of queuedWithdrawals != 0 satisfies

Vulnerability Details

In contract PriorityPool, When ever we call deposit we forward the call to _deposit after doing a check

Now here

File: PriorityPool.sol
601: function _deposit(
602: address _account,
603: uint256 _amount,
604: bool _shouldQueue,
605: bytes[] memory _data
606: ) internal {
.......
611: if (totalQueued == 0) {
612: uint256 queuedWithdrawals = withdrawalPool.getTotalQueuedWithdrawals();
613: if (queuedWithdrawals != 0) {
614: uint256 toDepositIntoQueue = toDeposit <= queuedWithdrawals
615: ? toDeposit
616: : queuedWithdrawals;
617: withdrawalPool.deposit(toDepositIntoQueue); //@audit no approval, this will always revert
618: toDeposit -= toDepositIntoQueue;
619: IERC20Upgradeable(address(stakingPool)).safeTransfer(_account, toDepositIntoQueue);
620: }

As you can see if Line 611 is satisfied it will query the queued withdrawals and fills it with the logic inside the if statement in Line 613

Now in Line 617 we call withdrawalPool.deposit But without giving any approvals

When we look at the logic inside withdrawalPool::deposit() we see

File: WithdrawalPool.sol
323: function deposit(uint256 _amount) external onlyPriorityPool {
324: token.safeTransferFrom(msg.sender, address(this), _amount);
325: lst.safeTransfer(msg.sender, _amount);
326: _finalizeWithdrawals(_amount);
327: }

It transfers the token (asset) from PriorityPool But this will always revert due to absence of approvals

As you see in PriorityPool::initialize() we give max approvals to _stakingPool but nothing about withdrawalPool

File: PriorityPool.sol
119: function initialize(
120: address _token,
121: address _stakingPool,
122: address _sdlPool,
123: uint128 _queueDepositMin,
124: uint128 _queueDepositMax
125: ) public initializer {
126: __UUPSUpgradeable_init();
127: __Ownable_init();
128: __Pausable_init();
129: token = IERC20Upgradeable(_token);
130: stakingPool = IStakingPool(_stakingPool);
131: sdlPool = ISDLPool(_sdlPool);
132: queueDepositMin = _queueDepositMin;
133: queueDepositMax = _queueDepositMax;
134: accounts.push(address(0));
135: token.safeIncreaseAllowance(_stakingPool, type(uint256).max);
136: }

Impact

PriorityPool::deposit() if totalQueued == 0 and queuedWithdrawals != 0

Tools Used

Manual review

Recommendations

Give approvals to withdrawalPoolwith amounts passed or give max approvals on initialization

Updates

Lead Judging Commences

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

Support

FAQs

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