contract VoxStrategyCurve3CRV is VoxStrategyCurveBase {
    // Curve stuff
    address public three_pool = 0xbEbc44782C7dB0a1A60Cb6fe97d0b483032FF1C7;
    address public three_gauge = 0xbFcF63294aD7105dEa65aA58F8AE5BE2D9d0952A;
    address public three_crv = 0x6c3F90f043a72FA612cbac8115EE7e52BDe6E490;

    constructor(
        address _governance,
        address _strategist,
        address _treasury,
        address _devfund,
        address _timelock,
        address _vault
    )
        public
        VoxStrategyCurveBase(
            three_pool,
            three_gauge,
            three_crv,
            _governance,
            _strategist,
            _treasury,
            _devfund,
            _timelock,
            _vault
        )
    {}

    // **** Views ****

    function getMostPremium()
        public
        override
        view
        returns (address, uint256)
    {
        uint256[] memory balances = new uint256[](3);
        balances[0] = ICurve3Pool(curve).balances(0); // DAI
        balances[1] = ICurve3Pool(curve).balances(1).mul(10**12); // USDC
        balances[2] = ICurve3Pool(curve).balances(2).mul(10**12); // USDT

        // DAI
        if (
            balances[0] < balances[1] &&
            balances[0] < balances[2]
        ) {
            return (dai, 0);
        }

        // USDC
        if (
            balances[1] < balances[0] &&
            balances[1] < balances[2]
        ) {
            return (usdc, 1);
        }

        // USDT
        if (
            balances[2] < balances[0] &&
            balances[2] < balances[1]
        ) {
            return (usdt, 2);
        }

        // If they're somehow equal, we just want DAI
        return (dai, 0);
    }

    function getName() external override pure returns (string memory) {
        return "VoxStrategyCurve3CRV";
    }

    // **** State Mutations ****

    function harvest() public restricted override {
        // stablecoin we want to convert to
        (address to, uint256 toIndex) = getMostPremium();

        // Collects crv tokens
        // Don't bother voting in v1
        ICurveMintr(mintr).mint(gauge);
        uint256 _crv = IERC20(crv).balanceOf(address(this));
        if (_crv > 0) {
            // x% is sent back to the rewards holder
            // to be used to lock up in as veCRV in a future date
            uint256 _keepCRV = _crv.mul(keepCRV).div(keepCRVMax);
            if (_keepCRV > 0) {
                IERC20(crv).safeTransfer(
                    treasury,
                    _keepCRV
                );
            }
            _crv = _crv.sub(_keepCRV);
            _swapUniswap(crv, to, _crv);
        }

        // Adds liquidity to curve.fi's pool
        // to get back want (3crv)
        uint256 _to = IERC20(to).balanceOf(address(this));
        if (_to > 0) {
            IERC20(to).safeApprove(curve, 0);
            IERC20(to).safeApprove(curve, _to);
            uint256[3] memory liquidity;
            liquidity[toIndex] = _to;
            ICurve3Pool(curve).add_liquidity(liquidity, 0);
        }

        _distributeAndDeposit();
    }
}
function getMostPremium()
    public
    override
    view
    returns (address, uint256)
{
    uint256[] memory balances = new uint256[](3);
    balances[0] = ICurve3Pool(curve).balances(0); // DAI
    balances[1] = ICurve3Pool(curve).balances(1).mul(10**12); // USDC
    balances[2] = ICurve3Pool(curve).balances(2).mul(10**12); // USDT

    // DAI
    if (
        balances[0] < balances[1] &&
        balances[0] < balances[2]
    ) {
        return (dai, 0);
    }

    // USDC
    if (
        balances[1] < balances[0] &&
        balances[1] < balances[2]
    ) {
        return (usdc, 1);
    }

    // USDT
    if (
        balances[2] < balances[0] &&
        balances[2] < balances[1]
    ) {
        return (usdt, 2);
    }

    // If they're somehow equal, we just want DAI
    return (dai, 0);
}

// **** Views ****