LOW severity: [VLTS3-13] Direct theft of surplus balance when unstaking stHYPE. **Severity:** Critical

**Path:** src/stHYPEWithdrawalModule.sol:update#L431-L475

**Description:** The stHYPE Withdrawal Module exposes functionality for the owner of the module to unstake stHYPE into HYPE using the Overseer contract. The owner calls `unstakeToken0Reserves`, which in turn...

Vulnerable code:
token1.deposit{value: balanceSurplus}();
// Pool reserves are measured as balances, hence we can replenish it with token1
// by transfering directly
token1.safeTransfer(stexInterface.pool(), balanceSurplus);

function _handleTokenInTransfersOnSwap(
        bool isZeroToOne,
        bool isSwapCallback,
        IERC20 token,
        uint256 amountInUsed,
        uint256 effectiveFee,
        bytes calldata _swapCallbackContext
    ) private {
        uint256 preBalance = token.balanceOf(sovereignVault);

        if (isSwapCallback) {
            ISovereignPoolSwapCallback(msg.sender).sovereignPoolSwapCallback(
                address(token),
                amountInUsed,
                _swapCallbackContext
            );
        } else {
            token.safeTransferFrom(msg.sender, sovereignVault, amountInUsed);
        }

        uint256 amountInReceived = token.balanceOf(sovereignVault) - preBalance;
        
        [..]
    }

function update() external nonReentrant {
        // Need to ensure that enough native token is reserved for settled LP withdrawals
        // WARNING: This implementation assumes that there is no slashing enabled in the LST protocol
        uint256 amountToken1ClaimableLPWithdrawalCache = amountToken1ClaimableLPWithdrawal;
        if (address(this).balance <= amountToken1ClaimableLPWithdrawalCache) {
            return;
        }

        // Having a surplus balance of native token means that new unstaking requests have been fulfilled
        uint256 balanceSurplus = address(this).balance - amountToken1ClaimableLPWithdrawalCache;
        // stHYPE is rebase, hence no need for conversion
        uint256 balanceSurplusToken0 = balanceSurplus;

        uint256 amountToken0PendingUnstakingCache = _amountToken0PendingUnstaking;
        if (amountToken0PendingUnstakingCache > balanceSurplusToken0) {
            _amountToken0PendingUnstaking = amountToken0PendingUnstakingCache - balanceSurplusToken0;
        } else {
            _amountToken0PendingUnstaking = 0;
        }

        // Prioritize LP withdrawal requests
        uint256 amountToken1PendingLPWithdrawalCache = amountToken1PendingLPWithdrawal;
        if (balanceSurplus > amountToken1PendingLPWithdrawalCache) {
            balanceSurplus -= amountToken1PendingLPWithdrawalCache;
            amountToken1ClaimableLPWithdrawal += amountToken1PendingLPWithdrawalCache;
            cumulativeAmountToken1ClaimableLPWithdrawal += amountToken1PendingLPWithdrawalCache;
            amountToken1PendingLPWithdrawal = 0;
        } else {
            amountToken1PendingLPWithdrawal -= balanceSurplus;
            amountToken1ClaimableLPWithdrawal += balanceSurplus;
            cumulativeAmountToken1ClaimableLPWithdrawal += balanceSurplus;
            balanceSurplus = 0;
            return;
        }

        // Wrap native token into token1 and re-deposit into the pool
        ISTEXAMM stexInterface = ISTEXAMM(stex);
        address token1Address = stexInterface.token1();
        IWETH9 token1 = IWETH9(token1Address);

        token1.deposit{value: balanceSurplus}();
        // Pool reserves are measured as balances, hence we can replenish it with token1
        // by transfering directly
        token1.safeTransfer(stexInterface.pool(), balanceSurplus);
    }