MEDIUM severity: [UFAR9] Investor withdrawals may not function with a nonzero withdrawalLockupPeriod. **Severity:** High

**Path:** contracts/main/contracts/pool/UFarmPool.sol#L517

**Description:** `UFarmPool::withdraw` allows for a permissionless two-step withdrawal process for non-member investors if a nonzero `withdrawalLockupPeriod` is set in the pool’s config. In this case,...

Vulnerable code:
//contracts/main/contracts/pool/UFarmPool.sol#L496-L540
...
    function withdraw(
        SignedWithdrawalRequest calldata _withdrawalRequest
    ) external override ufarmIsNotPaused nonReentrant {
        _checkStatusForFinancing(false);
        IPoolAdmin.PoolConfig memory config = IPoolAdmin(poolAdmin).getConfig();

        if (msg.sender == ufarmFund) {
            withdrawQueue.push(
                QueueItem(
                    _withdrawalRequest.body.sharesToBurn,
                    keccak256(abi.encode(blockhash(block.number), totalSupply())),
                    msg.sender,
                    valueToken
                )
            );
        } else {
            uint256 sharesToBurn;
            address investor;
            bytes32 withdrawalRequestHash;
            (investor, sharesToBurn, withdrawalRequestHash) = validateWithdrawalRequest(_withdrawalRequest);

            if (config.withdrawalLockupPeriod > 0) {
                if (pendingWithdrawalsRequests[withdrawalRequestHash] == 0) {
                    // Set the withdrawal request timestamp
                    pendingWithdrawalsRequests[withdrawalRequestHash] = block.timestamp;
                    emit WithdrawRequestReceived(investor, withdrawalRequestHash, block.timestamp);
                } else {
                    // Check if the lockup period has passed
                    uint256 unlockTime = pendingWithdrawalsRequests[withdrawalRequestHash] +
                        config.withdrawalLockupPeriod;
                    if (block.timestamp < unlockTime) {
                        // Safe because of the check above
                        revert LockupPeriodNotPassed(unlockTime);
                    } else {
                        _changeStatus(PoolStatus.Deactivating);
                    }
                }
                return;
            }

            withdrawQueue.push(QueueItem(sharesToBurn, withdrawalRequestHash, investor, valueToken));
        }

        sendQuexRequest();
    }
...

//contracts/main/contracts/pool/UFarmPool.sol#L496-L540
...
    function withdraw(
        SignedWithdrawalRequest calldata _withdrawalRequest
    ) external override ufarmIsNotPaused nonReentrant {
        ...
            if (config.withdrawalLockupPeriod > 0) {
               ...
                    if (block.timestamp < unlockTime) {
                        // Safe because of the check above
                        revert LockupPeriodNotPassed(unlockTime);
                    } else {
++                      if (status == PoolStatus.Deactivating) {
++                          withdrawQueue.push(QueueItem(sharesToBurn, withdrawalRequestHash, investor, valueToken));
++                          sendQuexRequest();
++                      }
++                      else {
++                          _changeStatus(PoolStatus.Deactivating);
                        }  
                    }
                }
                return;
            }
            withdrawQueue.push(QueueItem(sharesToBurn, withdrawalRequestHash, investor, valueToken));
        }

        sendQuexRequest();
    }
...

//contracts/main/contracts/pool/UFarmPool.sol#L496-L540
...
    function withdraw(
        SignedWithdrawalRequest calldata _withdrawalRequest
    ) external override ufarmIsNotPaused nonReentrant {
        ...
--            if (config.withdrawalLockupPeriod > 0) {
++            if (config.withdrawalLockupPeriod > 0 && (status != PoolStatus.Deactivating)) {
              ...
              }
              return;
            }

            withdrawQueue.push(QueueItem(sharesToBurn, withdrawalRequestHash, investor, valueToken));
        }

        sendQuexRequest();
    }
...