contract ERC20 is ERC20Data, Domain {
	event Transfer(address indexed _from, address indexed _to, uint256 _value);
	event Approval(address indexed _owner, address indexed _spender, uint256 _value);

	/**
	 * @dev Sets the values for {name} and {symbol}.
	 *
	 * The defaut value of {decimals} is 18. To select a different value for
	 * {decimals} you should overload it.
	 *
	 * All two of these values are immutable: they can only be set once during
	 * construction.
	 */
	constructor(string memory name_, string memory symbol_) public {
		name = name_;
		symbol = symbol_;
		decimals = 18;
	}

	/// @notice Transfers `amount` tokens from `msg.sender` to `to`.
	/// @param to The address to move the tokens.
	/// @param amount of the tokens to move.
	/// @return (bool) Returns True if succeeded.
	function transfer(address to, uint256 amount) public returns (bool) {
		// If `amount` is 0, or `msg.sender` is `to` nothing happens
		if (amount != 0) {
			uint256 srcBalance = balanceOf[msg.sender];
			require(srcBalance >= amount, "ERC20::transfer: balance too low");
			if (msg.sender != to) {
				require(to != address(0), "ERC20::transfer: no zero address"); // Moved down so low balance calls safe some gas

				balanceOf[msg.sender] = srcBalance - amount; // Underflow is checked
				balanceOf[to] += amount; // Can't overflow because totalSupply would be greater than 2^256-1
			}
		}
		emit Transfer(msg.sender, to, amount);
		return true;
	}

	/// @notice Transfers `amount` tokens from `from` to `to`. Caller needs approval for `from`.
	/// @param from Address to draw tokens from.
	/// @param to The address to move the tokens.
	/// @param amount The token amount to move.
	/// @return (bool) Returns True if succeeded.
	function transferFrom(
		address from,
		address to,
		uint256 amount
	) public returns (bool) {
		// If `amount` is 0, or `from` is `to` nothing happens
		if (amount != 0) {
			uint256 srcBalance = balanceOf[from];
			require(srcBalance >= amount, "ERC20::transferFrom: balance too low");

			if (from != to) {
				uint256 spenderAllowance = allowance[from][msg.sender];

				// If allowance is infinite, don't decrease it to save on gas (breaks with EIP-20).
				if (spenderAllowance != type(uint256).max) {
					require(spenderAllowance >= amount, "ERC20::transferFrom: allowance too low");
					allowance[from][msg.sender] = spenderAllowance - amount; // Underflow is checked
				}
				require(to != address(0), "ERC20::transferFrom: no zero address"); // Moved down so other failed calls safe some gas

				balanceOf[from] = srcBalance - amount; // Underflow is checked
				balanceOf[to] += amount; // Can't overflow because totalSupply would be greater than 2^256-1
			}
		}
		emit Transfer(from, to, amount);
		return true;
	}

	/// @notice Approves `amount` from sender to be spend by `spender`.
	/// @param spender Address of the party that can draw from msg.sender's account.
	/// @param amount The maximum collective amount that `spender` can draw.
	/// @return (bool) Returns True if approved.
	function approve(address spender, uint256 amount) public returns (bool) {
		allowance[msg.sender][spender] = amount;
		emit Approval(msg.sender, spender, amount);
		return true;
	}

	// solhint-disable-next-line func-name-mixedcase
	function DOMAIN_SEPARATOR() external view returns (bytes32) {
		return _domainSeparator();
	}

	// keccak256("Permit(address owner,address spender,uint256 value,uint256 nonce,uint256 deadline)");
	bytes32 private constant PERMIT_SIGNATURE_HASH = 0x6e71edae12b1b97f4d1f60370fef10105fa2faae0126114a169c64845d6126c9;

	/// @notice Approves `value` from `owner_` to be spend by `spender`.
	/// @param owner_ Address of the owner.
	/// @param spender The address of the spender that gets approved to draw from `owner_`.
	/// @param value The maximum collective amount that `spender` can draw.
	/// @param deadline This permit must be redeemed before this deadline (UTC timestamp in seconds).
	function permit(
		address owner_,
		address spender,
		uint256 value,
		uint256 deadline,
		uint8 v,
		bytes32 r,
		bytes32 s
	) external {
		require(owner_ != address(0), "ERC20::permit: Owner cannot be 0");
		require(block.timestamp < deadline, "ERC20: Expired");
		require(
			ecrecover(
				_getDigest(
					keccak256(abi.encode(PERMIT_SIGNATURE_HASH, owner_, spender, value, nonces[owner_]++, deadline))
				),
				v,
				r,
				s
			) == owner_,
			"ERC20::permit: Invalid Signature"
		);
		allowance[owner_][spender] = value;
		emit Approval(owner_, spender, value);
	}
}
function transferFrom(
	address from,
	address to,
	uint256 amount
) public returns (bool) {
	// If `amount` is 0, or `from` is `to` nothing happens
	if (amount != 0) {
		uint256 srcBalance = balanceOf[from];
		require(srcBalance >= amount, "ERC20::transferFrom: balance too low");

		if (from != to) {
			uint256 spenderAllowance = allowance[from][msg.sender];

			// If allowance is infinite, don't decrease it to save on gas (breaks with EIP-20).
			if (spenderAllowance != type(uint256).max) {
				require(spenderAllowance >= amount, "ERC20::transferFrom: allowance too low");
				allowance[from][msg.sender] = spenderAllowance - amount; // Underflow is checked
			}
			require(to != address(0), "ERC20::transferFrom: no zero address"); // Moved down so other failed calls safe some gas

			balanceOf[from] = srcBalance - amount; // Underflow is checked
			balanceOf[to] += amount; // Can't overflow because totalSupply would be greater than 2^256-1
		}
	}
	emit Transfer(from, to, amount);
	return true;
}

/// @notice Transfers `amount` tokens from `from` to `to`. Caller needs approval for `from`.
/// @param from Address to draw tokens from.
/// @param to The address to move the tokens.
/// @param amount The token amount to move.
/// @return (bool) Returns True if succeeded.