contract StrategyCvxV1 is StrategyBase {
    //want token CVX
    address public constant cvx = 0x4e3FBD56CD56c3e72c1403e103b45Db9da5B9D2B;

    // staking constants
    address public constant stakingPool = 0xCF50b810E57Ac33B91dCF525C6ddd9881B139332;
    address public constant rewardToken = 0x62B9c7356A2Dc64a1969e19C23e4f579F9810Aa7; //cvxCRV

    constructor(
        address _governance,
        address _strategist,
        address _controller,
        address _timelock
    )
        public StrategyBase(cvx, _governance, _strategist, _controller, _timelock)
    {		        
        IERC20(cvx).safeApprove(stakingPool, uint256(-1));
    }

    // **** State Mutations ****
	
    function deposit() public override {
        uint256 _wantAmt = IERC20(want).balanceOf(address(this));
        require(_wantAmt > 0, "!_wantAmt");
        ICvxRewardPool(stakingPool).stake(_wantAmt);
    }
	
    function _withdrawSome(uint256 _amount) internal override returns (uint256) {
        if (_amount == 0){
            return 0;
        }
        uint256 _beforeWant = IERC20(want).balanceOf(address(this));
        ICvxRewardPool(stakingPool).withdraw(_amount, false);
        uint256 _afterWant = IERC20(want).balanceOf(address(this));

        return _afterWant.sub(_beforeWant);
    }

    // Controller only function for creating additional rewards from dust
    function withdraw(IERC20 _asset) external override returns (uint256 balance) {
        require(address(_asset) != want, 'wantToken');
        balance = _withdrawNonWantAsset(_asset);
    }
	
    function _convertWantToBuyback(uint256 _lpAmount) internal override returns (address, uint256){
        require(_lpAmount > 0, '!_lpAmount');
        return (want, _lpAmount);
    }

    function harvest() public override onlyBenignCallers {

        // Collects reward tokens
        ICvxRewardPool(stakingPool).getReward(false);
		
        uint256 _reward = IERC20(rewardToken).balanceOf(address(this));

        if (_reward > 0) {
            //swap rewardToken to want
            address[] memory _swapPath = new address[](3);
            _swapPath[0] = rewardToken;
            _swapPath[1] = weth;
            _swapPath[2] = want;
            _swapUniswapWithDetailConfig(rewardToken, want, _reward, 1, _swapPath, sushiRouter);

            uint256 _wantAmount = IERC20(want).balanceOf(address(this));
            uint256 _buybackLpAmount = _wantAmount.mul(performanceFee).div(performanceMax);
            if (buybackEnabled == true && _buybackLpAmount > 0){
                (address _buybackPrinciple, uint256 _buybackAmount) = _convertWantToBuyback(_buybackLpAmount);
                buybackAndNotify(_buybackPrinciple, _buybackAmount);
            }

            uint256 _wantBal = IERC20(want).balanceOf(address(this));
            if(_wantBal > 0){
                lastHarvestBlock = block.number;
                lastHarvestInWant = _wantBal;
                deposit();
            }
        }
    }

    // **** Views ****
    function balanceOfPool() public override view returns (uint256){
        return ICvxRewardPool(stakingPool).balanceOf(address(this));
    }

    function getHarvestable() external view returns (uint256) {
        return ICvxRewardPool(stakingPool).earned(address(this));
    }
	
    function getName() external override pure returns (string memory) {
        return "StrategyCvxV1";
    }
}
function withdraw(IERC20 _asset) external override returns (uint256 balance) {
    require(address(_asset) != want, 'wantToken');
    balance = _withdrawNonWantAsset(_asset);
}

// Controller only function for creating additional rewards from dust