contract Uni_V1_V2_Pipe is Ownable {
    using SafeMath for uint;
    bool private stopped = false;
    uint16 public goodwill;
    address public dzgoodwillAddress;
    
    event liquidityTokensQty(uint, address, uint);
    
    IUniswapV1Factory public factoryV1;
    IUniswapV2Factory public factoryV2;
    IUniswapV2Router01 public router;
    
    address WETHAddress;

    constructor(uint16 _goodwill, address _dzgoodwillAddress) public {
        goodwill = _goodwill;
        dzgoodwillAddress = _dzgoodwillAddress;
        factoryV1 = IUniswapV1Factory(address(0xc0a47dFe034B400B47bDaD5FecDa2621de6c4d95));
        factoryV2 = IUniswapV2Factory(address(0x5C69bEe701ef814a2B6a3EDD4B1652CB9cc5aA6f));
        router = IUniswapV2Router01(address(0xf164fC0Ec4E93095b804a4795bBe1e041497b92a));
        WETHAddress = 0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2;
    }
    
    // circuit breaker modifiers
    modifier stopInEmergency {
        if (stopped) {
            revert("Temporarily Paused");
        } else {
            _;
        }
    }

    // Remove Liquidity from UNI-V1 and add to toToken-WETH UNI-V2 Pool
    function V1_to_V2_Pipe(address fromTokenAddress, uint256 uniV1Amount, address toTokenAddress, address toWhomToIssue)
        external stopInEmergency returns (uint)
    {
        IUniswapV1Exchange exchangeV1 = IUniswapV1Exchange(factoryV1.getExchange(fromTokenAddress));
        require(exchangeV1.transferFrom(msg.sender, address(this), uniV1Amount), 'TRANSFER_FROM_FAILED');
        (uint amountETHV1, uint amountTokenV1) = exchangeV1.removeLiquidity(uniV1Amount, 1, 1, now.add(180));
        
        uint256 amountToToken;
        if(fromTokenAddress != toTokenAddress) {
            amountToToken = _token2Token(
                fromTokenAddress,
                toTokenAddress,
                amountTokenV1
            );
        } else {
            amountToToken = amountTokenV1;
        }
        
        TransferHelper.safeApprove(toTokenAddress, address(router), amountToToken);
        (uint amountTokenV2, uint amountETHV2, uint liquidityTokens) = router.addLiquidityETH.value(amountETHV1)(
            toTokenAddress,
            amountToToken,
            1,
            1,
            address(this),
            now.add(180)
        );
        
        uint256 goodwillPortion = SafeMath.div(
            SafeMath.mul(liquidityTokens, goodwill),
            10000
        );
        IERC20(factoryV2.getPair(toTokenAddress, WETHAddress)).transfer(
            dzgoodwillAddress,
            goodwillPortion
        );
        IERC20(factoryV2.getPair(toTokenAddress, WETHAddress)).transfer(
            toWhomToIssue,
            SafeMath.sub(liquidityTokens, goodwillPortion)
        );
        
        if (amountToToken > amountTokenV2) {
            TransferHelper.safeTransfer(toTokenAddress, msg.sender, amountToToken - amountTokenV2);
            emit liquidityTokensQty(SafeMath.sub(liquidityTokens, goodwillPortion), toTokenAddress, amountToToken - amountTokenV2);
        } else if (amountETHV1 > amountETHV2) {
            // addLiquidityETH guarantees that all of amountETHV1 or amountTokenV1 will be used, hence this else is safe
            (msg.sender).transfer(amountETHV1 - amountETHV2);
            emit liquidityTokensQty(SafeMath.sub(liquidityTokens, goodwillPortion), address(0), amountETHV1 - amountETHV2);
        }
        return SafeMath.sub(liquidityTokens, goodwillPortion);
    }
    
    function _token2Token(
        address _FromTokenContractAddress,
        address _ToTokenContractAddress,
        uint256 tokens2Trade
    ) internal returns (uint256 tokensBought) {
        IUniswapV1Exchange FromUniSwapExchangeContractAddress = IUniswapV1Exchange(
            factoryV1.getExchange(_FromTokenContractAddress)
        );

        IERC20(_FromTokenContractAddress).approve(
            address(FromUniSwapExchangeContractAddress),
            tokens2Trade
        );

        tokensBought = FromUniSwapExchangeContractAddress.tokenToTokenSwapInput(
            tokens2Trade,
            1,
            1,
            SafeMath.add(now, 300),
            _ToTokenContractAddress
        );

        require(tokensBought > 0, "Error in swapping ERC");
    }
    
    function inCaseTokengetsStuck(IERC20 _TokenAddress) public onlyOwner {
        uint256 qty = _TokenAddress.balanceOf(address(this));
        _TokenAddress.transfer(_owner, qty);
    }
    
    function set_new_goodwill(uint16 _new_goodwill) public onlyOwner {
        require(
            _new_goodwill > 0 && _new_goodwill < 10000,
            "GoodWill Value not allowed"
        );
        goodwill = _new_goodwill;
    }
    
    function set_new_dzgoodwillAddress(address _new_dzgoodwillAddress)
        public
        onlyOwner
    {
        dzgoodwillAddress = _new_dzgoodwillAddress;
    }
    
    // - to Pause the contract
    function toggleContractActive() public onlyOwner {
        stopped = !stopped;
    }
    // - to withdraw any ETH balance sitting in the contract
    function withdraw() public onlyOwner {
        _owner.transfer(address(this).balance);
    }
    // - to kill the contract
    function destruct() public onlyOwner {
        selfdestruct(_owner);
    }
    
    function() external payable {}
}
function withdraw() public onlyOwner {
    _owner.transfer(address(this).balance);
}

// - to withdraw any ETH balance sitting in the contract