contract StrategyAlchemixALUSD is StrategyBase {
    address public constant alcx = 0xdBdb4d16EdA451D0503b854CF79D55697F90c8DF;
    address public constant alusd = 0xBC6DA0FE9aD5f3b0d58160288917AA56653660E9;
    address public constant stakingPool = 0xAB8e74017a8Cc7c15FFcCd726603790d26d7DeCa;
    address public constant dai = 0x6B175474E89094C44Da98b954EedeAC495271d0F;
    address public constant usdc = 0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48;
    address public constant curveSwapAlcx = 0x43b4FdFD4Ff969587185cDB6f0BD875c5Fc83f8c;
    uint256 public constant stakingPoolId = 0;

    constructor(address _governance, address _strategist, address _controller, address _timelock) public 
    StrategyBase(alusd, _governance, _strategist, _controller, _timelock)
    {	
        IERC20(alusd).safeApprove(stakingPool, uint256(-1));
        IERC20(alusd).safeApprove(curveSwapAlcx, uint256(-1)); 
        IERC20(dai).safeApprove(curveSwapAlcx, uint256(-1)); 
        IERC20(alcx).safeApprove(sushiRouter, uint256(-1)); 
        IERC20(usdc).safeApprove(univ2Router2, uint256(-1)); 
    }
	
    // **** Views ****

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

    function balanceOfPool() public override view returns (uint256) {
        return IAlchemixStakingPool(stakingPool).getStakeTotalDeposited(address(this), stakingPoolId);
    }

    function getHarvestable() external view returns (uint256) {
        return IAlchemixStakingPool(stakingPool).getStakeTotalUnclaimed(address(this), stakingPoolId);
    }	
	
    // **** Modifications ****

    function deposit() public override {
        uint256 _want = IERC20(want).balanceOf(address(this));
        if (_want > 0) {
            IAlchemixStakingPool(stakingPool).deposit(stakingPoolId, _want);
        }
    }

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

    function _withdrawSome(uint256 _amount) internal override returns (uint256){
        IAlchemixStakingPool(stakingPool).withdraw(stakingPoolId, _amount);
        return _amount;
    }
	
    function _convertWantToBuyback(uint256 _lpAmount) internal override returns (address, uint256){
        require(_lpAmount > 0, '!_lpAmount');		
        ICurveSwap(curveSwapAlcx).exchange_underlying(0, 2, _lpAmount, 0); // convert from alusd to usdc
        return (usdc, IERC20(usdc).balanceOf(address(this)));
    }

    function harvest() public override onlyBenevolent {
        // Collects ALCX tokens
        IAlchemixStakingPool(stakingPool).claim(stakingPoolId);
        uint256 _profit = IERC20(alcx).balanceOf(address(this));
        if (_profit > 0) {
            // convert from alcx to alusd: alcx -> eth -> dai -> alusd
            _swapUniswap(alcx, dai, _profit);
            ICurveSwap(curveSwapAlcx).exchange_underlying(1, 0, IERC20(dai).balanceOf(address(this)), 0); 
            uint256 _alusd = IERC20(alusd).balanceOf(address(this));
            (address _buybackPrinciple, uint256 _buybackAmount) = _convertWantToBuyback(_alusd.mul(performanceFee).div(performanceMax));
            buybackAndNotify(_buybackPrinciple, _buybackAmount);
            deposit();
        }
    }

    // Controller only function for creating additional rewards from dust
    function withdraw(IERC20 _asset) external override returns (uint256 balance) {
        balance = _withdrawNonWantAsset(_asset);
    }
}
function _withdrawSome(uint256 _amount) internal override returns (uint256){
    IAlchemixStakingPool(stakingPool).withdraw(stakingPoolId, _amount);
    return _amount;
}

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