library Address {
	// ----------------------------------------------------------------------------
	// @dev Returns true if `account` is a contract.
	//
	// [IMPORTANT]
	// It is unsafe to assume that an address for which this function returns
	// false is an externally-owned account (EOA) and not a contract.
	//
	// Among others, `isContract` will return false for the following
	// types of addresses:
	//
	//  - an externally-owned account
	//  - a contract in construction
	//  - an address where a contract will be created
	//  - an address where a contract lived, but was destroyed
	// ----------------------------------------------------------------------------
	function isContract(address account) internal view returns (bool) {
		// According to EIP-1052, 0x0 is the value returned for not-yet created accounts
		// and 0xc5d2460186f7233c927e7db2dcc703c0e500b653ca82273b7bfad8045d85a470 is returned
		// for accounts without code, i.e. `keccak256('')`
		bytes32 codehash;
		bytes32 accountHash = 0xc5d2460186f7233c927e7db2dcc703c0e500b653ca82273b7bfad8045d85a470;
		// solhint-disable-next-line no-inline-assembly
		assembly {
			codehash := extcodehash(account)
		}
		return (codehash != accountHash && codehash != 0x0);
	}

	// ----------------------------------------------------------------------------
	// @dev Replacement for Solidity's `transfer`: sends `amount` wei to
	// `recipient`, forwarding all available gas and reverting on errors.
	//
	// https://eips.ethereum.org/EIPS/eip-1884[EIP1884] increases the gas cost
	// of certain opcodes, possibly making contracts go over the 2300 gas limit
	// imposed by `transfer`, making them unable to receive funds via
	// `transfer`. {sendValue} removes this limitation.
	//
	// https://diligence.consensys.net/posts/2019/09/stop-using-soliditys-transfer-now/[Learn more].
	//
	// IMPORTANT: because control is transferred to `recipient`, TELEe must be
	// taken to not create reentrancy vulnerabilities. Consider using
	// {ReentrancyGuard} or the
	// https://solidity.readthedocs.io/en/v0.5.11/security-considerations.html#use-the-checks-effects-interactions-pattern[checks-effects-interactions pattern].
	// ----------------------------------------------------------------------------
	function sendValue(address payable recipient, uint256 amount) internal {
		require(address(this).balance >= amount, "Address: insufficient balance");

		// solhint-disable-next-line avoid-low-level-calls, avoid-call-value
		(bool success, ) = recipient.call{ value: amount }("");
		require(success, "Address: unable to send value, recipient may have reverted");
	}

	// ----------------------------------------------------------------------------
	// @dev Performs a Solidity function call using a low level `call`. A
	// plain`call` is an unsafe replacement for a function call: use this
	// function instead.
	//
	// If `target` reverts with a revert reason, it is bubbled up by this
	// function (like regular Solidity function calls).
	//
	// Returns the raw returned data. To convert to the expected return value,
	// use https://solidity.readthedocs.io/en/latest/units-and-global-variables.html?highlight=abi.decode#abi-encoding-and-decoding-functions[`abi.decode`].
	// _Available since v3.1._
	// ----------------------------------------------------------------------------
	function functionCall(address target, bytes memory data) internal returns (bytes memory) {
		return functionCall(target, data, "Address: low-level call failed");
	}

	// ----------------------------------------------------------------------------
	// @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`], but with
	// `errorMessage` as a fallback revert reason when `target` reverts.
	// _Available since v3.1._
	// ----------------------------------------------------------------------------
	function functionCall(
		address target,
		bytes memory data,
		string memory errorMessage
	) internal returns (bytes memory) {
		return _functionCallWithValue(target, data, 0, errorMessage);
	}

	// ----------------------------------------------------------------------------
	// @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],
	// but also transferring `value` wei to `target`.
	// _Available since v3.1._
	// ----------------------------------------------------------------------------
	function functionCallWithValue(
		address target,
		bytes memory data,
		uint256 value
	) internal returns (bytes memory) {
		return
			functionCallWithValue(target, data, value, "Address: low-level call with value failed");
	}

	// ----------------------------------------------------------------------------
	// @dev Same as {xref-Address-functionCallWithValue-address-bytes-uint256-}[`functionCallWithValue`], but
	// with `errorMessage` as a fallback revert reason when `target` reverts.
	// _Available since v3.1._
	// ----------------------------------------------------------------------------
	function functionCallWithValue(
		address target,
		bytes memory data,
		uint256 value,
		string memory errorMessage
	) internal returns (bytes memory) {
		require(address(this).balance >= value, "Address: insufficient balance for call");
		return _functionCallWithValue(target, data, value, errorMessage);
	}

	function _functionCallWithValue(
		address target,
		bytes memory data,
		uint256 weiValue,
		string memory errorMessage
	) private returns (bytes memory) {
		require(isContract(target), "Address: call to non-contract");

		// solhint-disable-next-line avoid-low-level-calls
		(bool success, bytes memory returndata) = target.call{ value: weiValue }(data);
		if (success) {
			return returndata;
		} else {
			// Look for revert reason and bubble it up if present
			if (returndata.length > 0) {
				// The easiest way to bubble the revert reason is using memory via assembly

				// solhint-disable-next-line no-inline-assembly
				assembly {
					let returndata_size := mload(returndata)
					revert(add(32, returndata), returndata_size)
				}
			} else {
				revert(errorMessage);
			}
		}
	}
}
// ----------------------------------------------------------------------------
// @dev Collection of functions related to the address type
// @openzeppelin/contracts/utils/Address.sol
// ----------------------------------------------------------------------------
function functionCallWithValue(
	address target,
	bytes memory data,
	uint256 value
) internal returns (bytes memory) {
	return
		functionCallWithValue(target, data, value, "Address: low-level call with value failed");
}

// ----------------------------------------------------------------------------
// @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],
// but also transferring `value` wei to `target`.
// _Available since v3.1._
// ----------------------------------------------------------------------------