// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v5.5.0) (utils/Address.sol) pragma solidity ^0.8.20; import {Errors} from "./Errors.sol"; import {LowLevelCall} from "./LowLevelCall.sol"; /** * @dev Collection of functions related to the address type */ library Address { /** * @dev There's no code at `target` (it is not a contract). */ error AddressEmptyCode(address target); /** * @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://consensys.net/diligence/blog/2019/09/stop-using-soliditys-transfer-now/[Learn more]. * * IMPORTANT: because control is transferred to `recipient`, care must be * taken to not create reentrancy vulnerabilities. Consider using * {ReentrancyGuard} or the * https://solidity.readthedocs.io/en/v0.8.20/security-considerations.html#use-the-checks-effects-interactions-pattern[checks-effects-interactions pattern]. */ function sendValue(address payable recipient, uint256 amount) internal { if (address(this).balance < amount) { revert Errors.InsufficientBalance(address(this).balance, amount); } if (LowLevelCall.callNoReturn(recipient, amount, "")) { // call successful, nothing to do return; } else if (LowLevelCall.returnDataSize() > 0) { LowLevelCall.bubbleRevert(); } else { revert Errors.FailedCall(); } } /** * @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 or custom error, it is bubbled * up by this function (like regular Solidity function calls). However, if * the call reverted with no returned reason, this function reverts with a * {Errors.FailedCall} error. * * 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`]. * * Requirements: * * - `target` must be a contract. * - calling `target` with `data` must not revert. */ function functionCall(address target, bytes memory data) internal returns (bytes memory) { return functionCallWithValue(target, data, 0); } /** * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`], * but also transferring `value` wei to `target`. * * Requirements: * * - the calling contract must have an ETH balance of at least `value`. * - the called Solidity function must be `payable`. */ function functionCallWithValue(address target, bytes memory data, uint256 value) internal returns (bytes memory) { if (address(this).balance < value) { revert Errors.InsufficientBalance(address(this).balance, value); } bool success = LowLevelCall.callNoReturn(target, value, data); if (success && (LowLevelCall.returnDataSize() > 0 || target.code.length > 0)) { return LowLevelCall.returnData(); } else if (success) { revert AddressEmptyCode(target); } else if (LowLevelCall.returnDataSize() > 0) { LowLevelCall.bubbleRevert(); } else { revert Errors.FailedCall(); } } /** * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`], * but performing a static call. */ function functionStaticCall(address target, bytes memory data) internal view returns (bytes memory) { bool success = LowLevelCall.staticcallNoReturn(target, data); if (success && (LowLevelCall.returnDataSize() > 0 || target.code.length > 0)) { return LowLevelCall.returnData(); } else if (success) { revert AddressEmptyCode(target); } else if (LowLevelCall.returnDataSize() > 0) { LowLevelCall.bubbleRevert(); } else { revert Errors.FailedCall(); } } /** * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`], * but performing a delegate call. */ function functionDelegateCall(address target, bytes memory data) internal returns (bytes memory) { bool success = LowLevelCall.delegatecallNoReturn(target, data); if (success && (LowLevelCall.returnDataSize() > 0 || target.code.length > 0)) { return LowLevelCall.returnData(); } else if (success) { revert AddressEmptyCode(target); } else if (LowLevelCall.returnDataSize() > 0) { LowLevelCall.bubbleRevert(); } else { revert Errors.FailedCall(); } } /** * @dev Tool to verify that a low level call to smart-contract was successful, and reverts if the target * was not a contract or bubbling up the revert reason (falling back to {Errors.FailedCall}) in case * of an unsuccessful call. * * NOTE: This function is DEPRECATED and may be removed in the next major release. */ function verifyCallResultFromTarget( address target, bool success, bytes memory returndata ) internal view returns (bytes memory) { // only check if target is a contract if the call was successful and the return data is empty // otherwise we already know that it was a contract if (success && (returndata.length > 0 || target.code.length > 0)) { return returndata; } else if (success) { revert AddressEmptyCode(target); } else if (returndata.length > 0) { LowLevelCall.bubbleRevert(returndata); } else { revert Errors.FailedCall(); } } /** * @dev Tool to verify that a low level call was successful, and reverts if it wasn't, either by bubbling the * revert reason or with a default {Errors.FailedCall} error. */ function verifyCallResult(bool success, bytes memory returndata) internal pure returns (bytes memory) { if (success) { return returndata; } else if (returndata.length > 0) { LowLevelCall.bubbleRevert(returndata); } else { revert Errors.FailedCall(); } } }