contract ExchangeHUSDC is Ownable, ReentrancyGuard {
	using SafeMath for uint256;
    using SafeERC20 for IERC20;
    using SafeERC20 for IToken;
    using Address for address;

    // Contract address of the Token contract sends out for In Token transfers
    IERC20 public outToken;
    // Contract address of the Token contract accepts
    IToken public inToken;    

    event Exchanged(address indexed user, uint256 amount);
    event Withdrawn(address indexed user, uint256 amount);
    event Burned(address indexed user, uint256 amount);

    /** 
    * @dev Exchange constructor
    * @param _outToken Out Token contract address
    * @param _inToken In Token contract address
    */
    constructor (
    	address _outToken,
    	address _inToken
    )
    	public
    {
        require(_inToken.isContract(), "address must be a contract");
    	setOutToken(_outToken);
        inToken = IToken(_inToken);
    } 

    /***************************************
                    ADMIN
    ****************************************/

    /** 
    * @dev Sets Out Token contract address, in case if proxy contract address changes
	* @param _tokenAddress - New Out Token contract address
	*/
    function setOutToken (
    	address _tokenAddress
    )
    	public
    	onlyOwner
    {
    	require(_tokenAddress.isContract(), "address must be a contract");
    	outToken = IERC20(_tokenAddress);
    }

    /** 
    * @dev Burns In Tokens
    * @param _amount - In Token units
    */
    function burnInTokens (
        uint256 _amount
    )
        public
        onlyOwner
    {
        require(_amount != 0, "amount is 0");
        inToken.burn(_amount);
        emit Burned(msg.sender, _amount);
    }

    /***************************************
                    ACTIONS
    ****************************************/
    
    /**
     * @dev Transfers In Tokens preapproved by sender to Exchange contract, 
     * transfers Out Tokens 1 to 1 to sender if there is balance of Out Tokens available
     * @param _amount of In Tokens
     */
    function receiveInToken (uint256 _amount)
        external
        nonReentrant
    {
    	require(_amount != 0, "amount is 0");
        require(outToken.balanceOf(address(this)) >= _amount, "not enough Out Tokens available");
    	address _user = msg.sender;
    	inToken.safeTransferFrom(_user, address(this), _amount);
        outToken.safeTransfer(_user, _amount);
        emit Exchanged(_user, _amount);
    }

    /***************************************
                    GETTERS
    ****************************************/

    /**
    * @dev Returns In Tokens balance
    */
    function getInTokenBalance()
        external
        view
        returns (uint256)
    {
        return inToken.balanceOf(address(this));
    }

    /**
    * @dev Returns Out Tokens balance
    */
    function getOutTokenBalance()
        external
        view
        returns(uint256) 
    {
        return outToken.balanceOf(address(this));
    }
    
}
// 
// Libs
// Used contracts
//Internal
function setOutToken (
	address _tokenAddress
)
	public
	onlyOwner
{
	require(_tokenAddress.isContract(), "address must be a contract");
	outToken = IERC20(_tokenAddress);
}

/** 
 * @dev Sets Out Token contract address, in case if proxy contract address changes
 	* @param _tokenAddress - New Out Token contract address
 	*/