contract Strategy is CurveVoterProxy {
    using SafeERC20 for IERC20;
    using Address for address;
    using SafeMath for uint256;

    address public constant pool = address(0x43b4FdFD4Ff969587185cDB6f0BD875c5Fc83f8c);
    address public constant alcx = address(0xdBdb4d16EdA451D0503b854CF79D55697F90c8DF);
    address[] public path;
    address[] public pathReward;

    constructor(address _vault) public CurveVoterProxy(_vault) {
        dex = sushiswap;
        curve = address(0xA79828DF1850E8a3A3064576f380D90aECDD3359);
        gauge = address(0x9582C4ADACB3BCE56Fea3e590F05c3ca2fb9C477);
        keepCRV = 1000;

        path = new address[](3);
        path[0] = crv;
        path[1] = weth;
        _setPath(0, false);
        pathReward = new address[](3);
        pathReward[0] = alcx;
        pathReward[1] = weth;
        _setPath(2, true);
    }

    function _setPath(uint _id, bool _isReward) internal {
        if (_id == 0) {
            if (_isReward) pathReward[2] = dai;
            else path[2] = dai;
        }
        else if (_id == 1) {
            if (_isReward) pathReward[2] = usdc;
            else path[2] = usdc;
        }
        else {
            if (_isReward) pathReward[2] = usdt;
            else path[2] = usdt;
        }
    }

    function setPath(uint _id, bool _isReward) external onlyAuthorized {
        _setPath(_id, _isReward);
    }

    function prepareReturn(uint256 _debtOutstanding)
        internal
        override
        returns (
            uint256 _profit,
            uint256 _loss,
            uint256 _debtPayment
        )
    {
        uint before = want.balanceOf(address(this));
        IVoterProxy(proxy).harvest(gauge);
        uint256 _crv = IERC20(crv).balanceOf(address(this));
        if (_crv > 0) {
            _crv = _adjustCRV(_crv);

            IERC20(crv).safeApprove(dex, 0);
            IERC20(crv).safeApprove(dex, _crv);

            Uni(dex).swapExactTokensForTokens(_crv, uint256(0), path, address(this), now);
        }
        IVoterProxy(proxy).claimRewards(gauge, alcx);
        uint256 _alcx = IERC20(alcx).balanceOf(address(this));
        if (_alcx > 0) {
            IERC20(alcx).safeApprove(sushiswap, 0);
            IERC20(alcx).safeApprove(sushiswap, _alcx);

            Uni(sushiswap).swapExactTokensForTokens(_alcx, uint256(0), pathReward, 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) {
            _add_liquidity(_dai, _usdc, _usdt);
        }
        _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 _add_liquidity(uint _dai, uint _usdc, uint _usdt) internal {
        if (_dai > 0) {
            IERC20(dai).safeApprove(curve, 0);
            IERC20(dai).safeApprove(curve, _dai);
        }
        if (_usdc > 0) {
            IERC20(usdc).safeApprove(curve, 0);
            IERC20(usdc).safeApprove(curve, _usdc);
        }
        if (_usdt > 0) {
            IERC20(usdt).safeApprove(curve, 0);
            IERC20(usdt).safeApprove(curve, _usdt);
        }
        ICurveFi(curve).add_liquidity(pool, [0, _dai, _usdc, _usdt], 0);
    }

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

    function protectedTokens()
        internal
        view
        override
        returns (address[] memory)
    {
        address[] memory protected = new address[](2);
        protected[0] = crv;
        protected[1] = alcx;
        return protected;
    }
}
function protectedTokens()
    internal
    view
    override
    returns (address[] memory)
{
    address[] memory protected = new address[](2);
    protected[0] = crv;
    protected[1] = alcx;
    return protected;
}

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