HIGH severity: User's funds are locked temporarily in the PriorityPool contract. **Severity:** Medium

**Description:** 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...

Vulnerable code:
function withdraw(uint256 _amount) external {//@audit-info LSD token
    if (_amount == 0) revert InvalidAmount();
    IERC20Upgradeable(address(stakingPool)).safeTransferFrom(msg.sender, address(this), _amount);//@audit-info get LSD token from the user
    _withdraw(msg.sender, _amount);
}

function _withdraw(address _account, uint256 _amount) internal {
    if (poolStatus == PoolStatus.CLOSED) revert WithdrawalsDisabled();

    uint256 toWithdrawFromQueue = _amount <= totalQueued ? _amount : totalQueued;//@audit-info if the queue is not empty, we use that first
    uint256 toWithdrawFromPool = _amount - toWithdrawFromQueue;

    if (toWithdrawFromQueue != 0) {
        totalQueued -= toWithdrawFromQueue;
        depositsSinceLastUpdate += toWithdrawFromQueue;//@audit-info regard this as a deposit via the queue
    }

    if (toWithdrawFromPool != 0) {
        stakingPool.withdraw(address(this), address(this), toWithdrawFromPool);//@audit-info withdraw from pool into this contract
    }

    //@audit-warning at this point, toWithdrawFromQueue of LSD tokens remain in this contract!

    token.safeTransfer(_account, _amount);//@audit-info
    emit Withdraw(_account, toWithdrawFromPool, toWithdrawFromQueue);
}

it('Cyfrin: user funds can be locked temporarily', async () => {
    // try deposit 1500 while the capacity is 1000
    await strategy.setMaxDeposits(toEther(1000))
    await sq.connect(signers[1]).deposit(toEther(1500), true)

    // 500 ether is queued for accounts[1]
    assert.equal(fromEther(await stakingPool.balanceOf(accounts[1])), 1000)
    assert.equal(fromEther(await sq.getQueuedTokens(accounts[1], 0)), 500)
    assert.equal(fromEther(await token.balanceOf(accounts[1])), 8500)
    assert.equal(fromEther(await sq.totalQueued()), 500)
    assert.equal(fromEther(await stakingPool.balanceOf(sq.address)), 0)

    // at this point user calls withdraw (maybe by mistake?)
    // withdraw swipes from the queue and the deposit room stays at zero
    await stakingPool.connect(signers[1]).approve(sq.address, toEther(500))
    await sq.connect(signers[1]).withdraw(toEther(500))

    // at this point getQueueTokens[accounts[1]] does not change but the queue is empty
    // user will think his queue position did not change and he can simply unqueue
    assert.equal(fromEther(await stakingPool.balanceOf(accounts[1])), 500)
    assert.equal(fromEther(await sq.getQueuedTokens(accounts[1], 0)), 500)
    assert.equal(fromEther(await token.balanceOf(accounts[1])), 9000)
    assert.equal(fromEther(await sq.totalQueued()), 0)
    // NOTE: at this point 500 ethers of LSD tokens are locked in the queue contract
    assert.equal(fromEther(await stakingPool.balanceOf(sq.address)), 500)

    // but unqueueTokens fails because actual totalQueued is zero
    await expect(sq.connect(signers[1]).unqueueTokens(0, 0, [], toEther(500))).to.be.revertedWith(
      'InsufficientQueuedTokens()'
    )

    // user's LSD tokens are still locked in the queue contract
    await stakingPool.connect(signers[1]).approve(sq.address, toEther(500))
    await sq.connect(signers[1]).withdraw(toEther(500))
    assert.equal(fromEther(await stakingPool.balanceOf(accounts[1])), 0)
    assert.equal(fromEther(await sq.getQueuedTokens(accounts[1], 0)), 500)
    assert.equal(fromEther(await token.balanceOf(accounts[1])), 9500)
    assert.equal(fromEther(await sq.totalQueued()), 0)
    assert.equal(fromEther(await stakingPool.balanceOf(sq.address)), 500)

    // user might try withdraw again but it will revert because user does not have any LSD tokens
    await stakingPool.connect(signers[1]).approve(sq.address, toEther(500))
    await expect(sq.connect(signers[1]).withdraw(toEther(500))).to.be.revertedWith(
      'Transfer amount exceeds balance'
    )

    // in conclusion, user's LSD tokens are locked in the queue contract and he cannot withdraw them
    // it is worth noting that the locked LSD tokens are credited once updateDistribution is called
    // so the lock is temporary
  })