abstract contract BaseStrategyMultiSwapper is BaseStrategy {
    using SafeERC20Upgradeable for IERC20Upgradeable;
    using AddressUpgradeable for address;
    using SafeMathUpgradeable for uint256;

    address public constant sushiswap = 0xd9e1cE17f2641f24aE83637ab66a2cca9C378B9F; // Sushiswap router

    /// @notice Swap specified balance of given token on Uniswap with given path
    function _swap_uniswap(
        address startToken,
        uint256 balance,
        address[] memory path
    ) internal {
        _safeApproveHelper(startToken, uniswap, balance);
        IUniswapRouterV2(uniswap).swapExactTokensForTokens(balance, 0, path, address(this), now);
    }

    /// @notice Swap specified balance of given token on Uniswap with given path
    function _swap_sushiswap(
        address startToken,
        uint256 balance,
        address[] memory path
    ) internal {
        _safeApproveHelper(startToken, sushiswap, balance);
        IUniswapRouterV2(sushiswap).swapExactTokensForTokens(balance, 0, path, address(this), now);
    }

    function _swapEthIn_uniswap(uint256 balance, address[] memory path) internal {
        IUniswapRouterV2(uniswap).swapExactETHForTokens{value: balance}(0, path, address(this), now);
    }

    function _swapEthIn_sushiswap(uint256 balance, address[] memory path) internal {
        IUniswapRouterV2(sushiswap).swapExactETHForTokens{value: balance}(0, path, address(this), now);
    }

    function _swapEthOut_uniswap(
        address startToken,
        uint256 balance,
        address[] memory path
    ) internal {
        _safeApproveHelper(startToken, uniswap, balance);
        IUniswapRouterV2(uniswap).swapExactTokensForETH(balance, 0, path, address(this), now);
    }

    function _swapEthOut_sushiswap(
        address startToken,
        uint256 balance,
        address[] memory path
    ) internal {
        _safeApproveHelper(startToken, sushiswap, balance);
        IUniswapRouterV2(sushiswap).swapExactTokensForETH(balance, 0, path, address(this), now);
    }

    /// @notice Add liquidity to uniswap for specified token pair, utilizing the maximum balance possible
    function _add_max_liquidity_sushiswap(address token0, address token1) internal {
        uint256 _token0Balance = IERC20Upgradeable(token0).balanceOf(address(this));
        uint256 _token1Balance = IERC20Upgradeable(token1).balanceOf(address(this));

        _safeApproveHelper(token0, sushiswap, _token0Balance);
        _safeApproveHelper(token1, sushiswap, _token1Balance);

        IUniswapRouterV2(sushiswap).addLiquidity(token0, token1, _token0Balance, _token1Balance, 0, 0, address(this), block.timestamp);
    }

    uint256[50] private __gap;
}
/*
 Expands swapping functionality over base strategy
 - ETH in and ETH out Variants
 - Sushiswap support in addition to Uniswap
 */
function _add_max_liquidity_sushiswap(address token0, address token1) internal {
    uint256 _token0Balance = IERC20Upgradeable(token0).balanceOf(address(this));
    uint256 _token1Balance = IERC20Upgradeable(token1).balanceOf(address(this));

    _safeApproveHelper(token0, sushiswap, _token0Balance);
    _safeApproveHelper(token1, sushiswap, _token1Balance);

    IUniswapRouterV2(sushiswap).addLiquidity(token0, token1, _token0Balance, _token1Balance, 0, 0, address(this), block.timestamp);
}

/// @notice Add liquidity to uniswap for specified token pair, utilizing the maximum balance possible