contract Strategy is ConvexMisc {
    address public constant link = address(0x514910771AF9Ca656af840dff83E8264EcF986CA);

    constructor(address _vault) public ConvexMisc(_vault) {
        curve = address(0xF178C0b5Bb7e7aBF4e12A4838C7b7c5bA2C623c0);
        id = 30;
        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();
    }

    function _approveBasic() internal override {
        super._approveBasic();
        IERC20(link).safeApprove(curve, 0);
        IERC20(link).safeApprove(curve, type(uint256).max);
    }

    // >>> approve other rewards on dex
    // function _approveDex() internal override { super._approveDex(); }

    // >>> include other rewards
    // function _migrateRewards(address _newStrategy) internal override { super._migrateRewards(_newStrategy); }

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

    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] = link;

            Uni(dex).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] = link;

            Uni(sushiswap).swapExactTokensForTokens(_cvx, uint256(0), path, address(this), now);
        }
        uint256 _link = IERC20(link).balanceOf(address(this));
        if (_link > 0) {
            ICurveFi(curve).add_liquidity([_link, 0], 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[](2);
        protected[0] = crv;
        protected[1] = cvx;
        return protected;
    }
}
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] = link;

        Uni(dex).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] = link;

        Uni(sushiswap).swapExactTokensForTokens(_cvx, uint256(0), path, address(this), now);
    }
    uint256 _link = IERC20(link).balanceOf(address(this));
    if (_link > 0) {
        ICurveFi(curve).add_liquidity([_link, 0], 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));
    }
}

// >>> approve other rewards on dex
// function _approveDex() internal override { super._approveDex(); }
// >>> include other rewards
// function _migrateRewards(address _newStrategy) internal override { super._migrateRewards(_newStrategy); }
// >>> include all other rewards in eth besides _claimableBasicInETH()
// function _claimableInETH() internal override view returns (uint256 _claimable) { _claimable = super._claimableInETH(); }