contract Strategy is ConvexStable {
    address public constant pool = address(0xEd279fDD11cA84bEef15AF5D39BB4d4bEE23F0cA);
    address public constant lqty = address(0x6DEA81C8171D0bA574754EF6F8b412F2Ed88c54D);
    address[] public pathTarget;

    constructor(address _vault) public ConvexStable(_vault) {
        curve = address(0xA79828DF1850E8a3A3064576f380D90aECDD3359);
        id = 33;
        isClaimRewards = true; // default is true, turn off in emergency
        isClaimExtras = true; // add this if there are extra rewards

        (address _lp,,,address _reward,,) = Booster(booster).poolInfo(id);
        require(_lp == address(want), "constructor: incorrect lp token");
        rewardContract = _reward;

        _approveBasic();
        pathTarget = new address[](3);
        _setPathTarget(0, 0); // crv path target
        _setPathTarget(1, 0); // cvx path target
        _setPathTarget(2, 0); // lqty path target

        dex = new address[](3);
        dex[0] = sushiswap; // crv
        dex[1] = sushiswap; // cvx
        dex[2] = uniswapv3; // lqty
        _approveDex();
    }

    // >>> approve other rewards on dex
    function _approveDex() internal override {
        super._approveDex();
        IERC20(lqty).approve(dex[2], 0);
        IERC20(lqty).approve(dex[2], type(uint256).max);
    }

    // >>> include other rewards
    function _migrateRewards(address _newStrategy) internal override {
        super._migrateRewards(_newStrategy);
        IERC20(lqty).safeTransfer(_newStrategy, IERC20(lqty).balanceOf(address(this)));
    }

    // >>> include all other rewards in eth besides _claimableBasicInETH()
    function _claimableInETH() internal override view returns (uint256 _claimable) {
        _claimable = super._claimableInETH();

        uint256 _lqty = IERC20(lqty).balanceOf(address(this));
        if (_lqty > 0) {
            address _dex = dex[2];
            if (_dex == uniswapv3) {
                uint256 amountOut = Uni(quoter).quoteExactInput(abi.encodePacked(lqty, uint24(3000), weth), _lqty);
                _claimable = _claimable.add(amountOut);
            }
            else if (_dex == uniswap) {
                address[] memory path = new address[](2);
                path[0] = lqty;
                path[1] = weth;
                uint256[] memory swap = Uni(_dex).getAmountsOut(_lqty, path);
                _claimable = _claimable.add(swap[1]);
            }
        }
    }

    function _setPathTarget(uint _tokenId, uint _id) internal {
        if (_id == 0) { 
            pathTarget[_tokenId] = dai;
        }
        else if (_id == 1) {
            pathTarget[_tokenId] = usdc;
        }
        else {
            pathTarget[_tokenId] = usdt;
        }
    }

    function setPathTarget(uint _tokenId, uint _id) external onlyAuthorized {
        _setPathTarget(_tokenId, _id);
    }

    function prepareReturn(uint256 _debtOutstanding)
        internal
        override
        returns (
            uint256 _profit,
            uint256 _loss,
            uint256 _debtPayment
        )
    {
        uint before = balanceOfWant();
        Rewards(rewardContract).getReward(address(this), isClaimExtras);
        uint256 _crv = IERC20(crv).balanceOf(address(this));
        if (_crv > 0) {
            _crv = _adjustCRV(_crv);

            address[] memory path = new address[](3);
            path[0] = crv;
            path[1] = weth;
            path[2] = pathTarget[0];

            Uni(dex[0]).swapExactTokensForTokens(_crv, uint256(0), path, address(this), now);
        }
        uint256 _cvx = IERC20(cvx).balanceOf(address(this));
        if (_cvx > 0) {
            address[] memory path = new address[](3);
            path[0] = cvx;
            path[1] = weth;
            path[2] = pathTarget[1];

            Uni(dex[1]).swapExactTokensForTokens(_cvx, uint256(0), path, address(this), now);
        }
        uint256 _lqty = IERC20(lqty).balanceOf(address(this));
        if (_lqty > 0) {
            address _dex = dex[2];
            if (_dex == uniswapv3) {
                Uni(_dex).exactInput(Uni.ExactInputParams(
                    abi.encodePacked(
                        lqty,
                        uint24(3000),
                        weth,
                        uint24(3000),
                        pathTarget[2]
                    ),
                    address(this),
                    now,
                    _lqty,
                    uint256(0)
                ));
            }
            else if (_dex == uniswap) {
                address[] memory path = new address[](3);
                path[0] = lqty;
                path[1] = weth;
                path[2] = pathTarget[2];

                Uni(_dex).swapExactTokensForTokens(_lqty, uint256(0), path, address(this), now);
            }
        }
        uint256 _dai = IERC20(dai).balanceOf(address(this));
        uint256 _usdc = IERC20(usdc).balanceOf(address(this));
        uint256 _usdt = IERC20(usdt).balanceOf(address(this));
        if (_dai > 0 || _usdc > 0 || _usdt > 0) {
            ICurveFi(curve).add_liquidity(pool, [0, _dai, _usdc, _usdt], 0);
        }
        _profit = want.balanceOf(address(this)).sub(before);

        uint _total = estimatedTotalAssets();
        uint _debt = vault.strategies(address(this)).totalDebt;
        if(_total < _debt) {
            _loss = _debt - _total;
            _profit = 0;
        }

        if (_debtOutstanding > 0) {
            _withdrawSome(_debtOutstanding);
            _debtPayment = Math.min(_debtOutstanding, balanceOfWant().sub(_profit));
        }
    }

    function protectedTokens()
        internal
        view
        override
        returns (address[] memory)
    {
        address[] memory protected = new address[](3);
        protected[0] = crv;
        protected[1] = cvx;
        protected[2] = lqty;
        return protected;
    }
}
function _claimableInETH() internal override view returns (uint256 _claimable) {
    _claimable = super._claimableInETH();

    uint256 _lqty = IERC20(lqty).balanceOf(address(this));
    if (_lqty > 0) {
        address _dex = dex[2];
        if (_dex == uniswapv3) {
            uint256 amountOut = Uni(quoter).quoteExactInput(abi.encodePacked(lqty, uint24(3000), weth), _lqty);
            _claimable = _claimable.add(amountOut);
        }
        else if (_dex == uniswap) {
            address[] memory path = new address[](2);
            path[0] = lqty;
            path[1] = weth;
            uint256[] memory swap = Uni(_dex).getAmountsOut(_lqty, path);
            _claimable = _claimable.add(swap[1]);
        }
    }
}

// >>> include all other rewards in eth besides _claimableBasicInETH()