contract Strategy is CurveVoterProxy {
    address public constant usdt = address(0xdAC17F958D2ee523a2206206994597C13D831ec7);
    address public constant wbtc = address(0x2260FAC5E5542a773Aa44fBCfeDf7C193bc2C599);
    address[] public pathTarget;

    constructor(address _vault) public CurveVoterProxy(_vault) {
        curve = address(0xD51a44d3FaE010294C616388b506AcdA1bfAAE46);
        gauge = address(0xDeFd8FdD20e0f34115C7018CCfb655796F6B2168);
        keepCRV = 1000;

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

        dex = new address[](1);
        dex[0] = sushiswap; // crv
        _approveDex();
    }

    // >>> approve the target token on curve
    function _approveBasic() internal override {
        IERC20(usdt).safeApprove(curve, 0);
        IERC20(usdt).safeApprove(curve, type(uint256).max);
        IERC20(wbtc).safeApprove(curve, 0);
        IERC20(wbtc).safeApprove(curve, type(uint256).max);
        IERC20(weth).safeApprove(curve, 0);
        IERC20(weth).safeApprove(curve, type(uint256).max);
    }

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

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

    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();
        IVoterProxy(proxy).harvest(gauge);
        uint256 _crv = IERC20(crv).balanceOf(address(this));
        if (_crv > 0) {
            _crv = _adjustCRV(_crv);

            address[] memory path;
            if (pathTarget[0] == weth) {
                path = new address[](2);
                path[0] = crv;
                path[1] = weth;
            }
            else {
                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 _usdt = IERC20(usdt).balanceOf(address(this));
        uint256 _wbtc = IERC20(wbtc).balanceOf(address(this));
        uint256 _weth = IERC20(weth).balanceOf(address(this));
        if (_usdt > 0 || _wbtc > 0 || _weth > 0) {
            ICurveFi(curve).add_liquidity([_usdt, _wbtc, _weth], 0);
        }
        _profit = balanceOfWant().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));
        }
    }

    // NOTE: Can override `tendTrigger` and `harvestTrigger` if necessary

    function protectedTokens()
        internal
        view
        override
        returns (address[] memory)
    {
        address[] memory protected = new address[](1);
        protected[0] = crv;
        return protected;
    }
}
function _approveBasic() internal override {
    IERC20(usdt).safeApprove(curve, 0);
    IERC20(usdt).safeApprove(curve, type(uint256).max);
    IERC20(wbtc).safeApprove(curve, 0);
    IERC20(wbtc).safeApprove(curve, type(uint256).max);
    IERC20(weth).safeApprove(curve, 0);
    IERC20(weth).safeApprove(curve, type(uint256).max);
}

// >>> approve the target token on curve