    function rebalance(uint256 directionMask, uint256 amountIn, uint256 amountOut) external nonReentrant {
        uint256 balanceBefore = IERC20(weth).balanceOf(address(this));
        bytes memory data = abi.encode(directionMask, amountIn, amountOut);
>>      IMorpho(morphoVault).flashLoan(weth, amountIn, data);
        uint256 balanceAfter = IERC20(weth).balanceOf(address(this));
        uint256 profit = balanceAfter - balanceBefore;
        require(profit > 0, "No profit made");
    }
    function onMorphoFlashLoan(uint256 assets, bytes calldata data) external {
        require(msg.sender == address(morphoVault), "Caller is not morphoVault");
        (uint256 directionMask, uint256 amountIn, uint256 amountOut) = abi.decode(data, (uint256, uint256, uint256));
        require(amountIn == assets, "Amount in does not match assets");

        uint256 _v3pool = uint256(uint160(uniswapPool)) | (directionMask);
        uint256[] memory pools = new uint256[](1);
        pools[0] = _v3pool;

        if (directionMask == _BUY_MASK) {
>>          _executeBuy(amountIn, pools);
        } else {
>>          _executeSell(amountIn, pools);
        }

        require(IERC20(weth).approve(address(morphoVault), assets), "Approve failed");
    }
    function _executeBuy(uint256 amountIn, uint256[] memory pools) internal {
        uint256 initialBalance = address(this).balance;

        // Execute buy
        require(IERC20(weth).approve(address(OKXTokenApprove), amountIn), "Approve failed");
>>      uint256 uniswapV3AmountOut = IDexRouter(OKXRouter).uniswapV3SwapTo(
            uint256(uint160(address(this))),
            amountIn,
            0,
            pools
        );
        VirtualToken(veth).cashOut(uniswapV3AmountOut);

        // SlowMist [N11]
        uint256 newBalance = address(this).balance - initialBalance;
        if (newBalance > 0) {
            IWETH(weth).deposit{value: newBalance}();
        }
    }

    function _executeSell(uint256 amountIn, uint256[] memory pools) internal {
        IWETH(weth).withdraw(amountIn);
        VirtualToken(veth).cashIn{value: amountIn}(amountIn);
>>      require(IERC20(veth).approve(address(OKXTokenApprove), amountIn), "Approve failed");
        IDexRouter(OKXRouter).uniswapV3SwapTo(uint256(uint160(address(this))), amountIn, 0, pools);
    }
    function _uniswapV3SwapTo(
        address payer,
        uint256 receiver,
        uint256 amount,
        uint256 minReturn,
        uint256[] calldata pools
    ) internal returns (uint256 returnAmount) {
        CommissionInfo memory commissionInfo = _getCommissionInfo();

        (
            address middleReceiver,
            uint256 balanceBefore
>>      ) = _doCommissionFromToken(
                commissionInfo,
                address(uint160(receiver)),
                amount
            );

        (uint256 swappedAmount, ) = _uniswapV3Swap(
            payer,
            payable(middleReceiver),
            amount,
            minReturn,
            pools
        );

>>      uint256 commissionAmount = _doCommissionToToken(
            commissionInfo,
            address(uint160(receiver)),
            balanceBefore
        );

        return swappedAmount - commissionAmount;
    }
    function _doCommissionFromToken(
        CommissionInfo memory commissionInfo,
        address receiver,
        uint256 inputAmount
    ) internal returns (address, uint256) {
//...
            let rate := mload(add(commissionInfo, 0x40))
>>          if gt(rate, commissionRateLimit) {
                _revertWithReason(
                    0x0000001b6572726f7220636f6d6d697373696f6e2072617465206c696d697400,
                    0x5f
                ) //"error commission rate limit"
            }
//...
    function _doCommissionToToken(
        CommissionInfo memory commissionInfo,
        address receiver,
        uint256 balanceBefore
    ) internal returns (uint256 amount) {
        if (!commissionInfo.isToTokenCommission) {
            return 0;
        }
//...
            let rate := mload(add(commissionInfo, 0x40))
>>           if gt(rate, commissionRateLimit) {
                _revertWithReason(
                    0x0000001b6572726f7220636f6d6d697373696f6e2072617465206c696d697400,
                    0x5f
                ) //"error commission rate limit"
            }
//...
