User's funds are locked temporarily in the PriorityPool contract
The protocol intended to utilize the deposit queue for withdrawal to minimize the stake/unstake interaction with the staking pool. When a user wants to withdraw, they are supposed to call the function `PriorityPool::withdraw()` with the desired amount as a parameter.\\n```\\nfunction withdraw(uint256 _amount) external {//@audit-info LSD token\\n    if (_amount == 0) revert InvalidAmount();\\n    IERC20Upgradeable(address(stakingPool)).safeTransferFrom(msg.sender, address(this), _amount);//@audit-info get LSD token from the user\\n    _withdraw(msg.sender, _amount);\\n}\\n```\\n\\nAs we can see in the implementation, the protocol pulls the `_amount` of LSD tokens from the user first and then calls `_withdraw()` where the actual withdrawal utilizing the queue is processed.\\n```\\nfunction _withdraw(address _account, uint256 _amount) internal {\\n    if (poolStatus == PoolStatus.CLOSED) revert WithdrawalsDisabled();\\n\\n    uint256 toWithdrawFromQueue = _amount <= totalQueued ? _amount : totalQueued;//@audit-info if the queue is not empty, we use that first\\n    uint256 toWithdrawFromPool = _amount - toWithdrawFromQueue;\\n\\n    if (toWithdrawFromQueue != 0) {\\n        totalQueued -= toWithdrawFromQueue;\\n        depositsSinceLastUpdate += toWithdrawFromQueue;//@audit-info regard this as a deposit via the queue\\n    }\\n\\n    if (toWithdrawFromPool != 0) {\\n        stakingPool.withdraw(address(this), address(this), toWithdrawFromPool);//@audit-info withdraw from pool into this contract\\n    }\\n\\n    //@audit-warning at this point, toWithdrawFromQueue of LSD tokens remain in this contract!\\n\\n    token.safeTransfer(_account, _amount);//@audit-info\\n    emit Withdraw(_account, toWithdrawFromPool, toWithdrawFromQueue);\\n}\\n```\\n\\nBut looking in the function `_withdraw()`, only `toWithdrawFromPool` amount of LSD tokens are withdrawn (burn) from the staking pool and `toWithdrawFromQueue` amount of LSD tokens remain in the `PriorityPool` contract. On the other hand, the contract tracks the queued amount for users by the mapping `accountQueuedTokens` and this leads to possible mismatch in the accounting. Due to this mismatch, a user's LSD tokens can be locked in the `PriorityPool` contract while the user sees his queued amount (getQueuedTokens()) is positive. Users can claim the locked LSD tokens once the function `updateDistribution` is called. Through the communication with the protocol team, it is understood that `updateDistribution` is expected to be called probably every 1-2 days unless there were any new deposits into the staking pool. So it means user's funds can be locked temporarily in the contract which is unfair for the user.
Consider add a feature to allow users to withdraw LSD tokens from the contract directly.
User's LSD tokens can be locked temporarily in the PriorityPool contract\\nProof of Concept:\\n```\\n it('Cyfrin: user funds can be locked temporarily', async () => {\\n    // try deposit 1500 while the capacity is 1000\\n    await strategy.setMaxDeposits(toEther(1000))\\n    await sq.connect(signers[1]).deposit(toEther(1500), true)\\n\\n    // 500 ether is queued for accounts[1]\\n    assert.equal(fromEther(await stakingPool.balanceOf(accounts[1])), 1000)\\n    assert.equal(fromEther(await sq.getQueuedTokens(accounts[1], 0)), 500)\\n    assert.equal(fromEther(await token.balanceOf(accounts[1])), 8500)\\n    assert.equal(fromEther(await sq.totalQueued()), 500)\\n    assert.equal(fromEther(await stakingPool.balanceOf(sq.address)), 0)\\n\\n    // at this point user calls withdraw (maybe by mistake?)\\n    // withdraw swipes from the queue and the deposit room stays at zero\\n    await stakingPool.connect(signers[1]).approve(sq.address, toEther(500))\\n    await sq.connect(signers[1]).withdraw(toEther(500))\\n\\n    // at this point getQueueTokens[accounts[1]] does not change but the queue is empty\\n    // user will think his queue position did not change and he can simply unqueue\\n    assert.equal(fromEther(await stakingPool.balanceOf(accounts[1])), 500)\\n    assert.equal(fromEther(await sq.getQueuedTokens(accounts[1], 0)), 500)\\n    assert.equal(fromEther(await token.balanceOf(accounts[1])), 9000)\\n    assert.equal(fromEther(await sq.totalQueued()), 0)\\n    // NOTE: at this point 500 ethers of LSD tokens are locked in the queue contract\\n    assert.equal(fromEther(await stakingPool.balanceOf(sq.address)), 500)\\n\\n    // but unqueueTokens fails because actual totalQueued is zero\\n    await expect(sq.connect(signers[1]).unqueueTokens(0, 0, [], toEther(500))).to.be.revertedWith(\\n      'InsufficientQueuedTokens()'\\n    )\\n\\n    // user's LSD tokens are still locked in the queue contract\\n    await stakingPool.connect(signers[1]).approve(sq.address, toEther(500))\\n    await sq.connect(signers[1]).withdraw(toEther(500))\\n    assert.equal(fromEther(await stakingPool.balanceOf(accounts[1])), 0)\\n    assert.equal(fromEther(await sq.getQueuedTokens(accounts[1], 0)), 500)\\n    assert.equal(fromEther(await token.balanceOf(accounts[1])), 9500)\\n    assert.equal(fromEther(await sq.totalQueued()), 0)\\n    assert.equal(fromEther(await stakingPool.balanceOf(sq.address)), 500)\\n\\n    // user might try withdraw again but it will revert because user does not have any LSD tokens\\n    await stakingPool.connect(signers[1]).approve(sq.address, toEther(500))\\n    await expect(sq.connect(signers[1]).withdraw(toEther(500))).to.be.revertedWith(\\n      'Transfer amount exceeds balance'\\n    )\\n\\n    // in conclusion, user's LSD tokens are locked in the queue contract and he cannot withdraw them\\n    // it is worth noting that the locked LSD tokens are credited once updateDistribution is called\\n    // so the lock is temporary\\n  })\\n```\\n
```\\nfunction withdraw(uint256 _amount) external {//@audit-info LSD token\\n    if (_amount == 0) revert InvalidAmount();\\n    IERC20Upgradeable(address(stakingPool)).safeTransferFrom(msg.sender, address(this), _amount);//@audit-info get LSD token from the user\\n    _withdraw(msg.sender, _amount);\\n}\\n```\\n