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);
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 withdrawalPool
with amounts passed or give max approvals on initialization