|
@@ -132,10 +132,8 @@ library Address {
|
|
|
string memory errorMessage
|
|
|
) internal returns (bytes memory) {
|
|
|
require(address(this).balance >= value, "Address: insufficient balance for call");
|
|
|
- require(isContract(target), "Address: call to non-contract");
|
|
|
-
|
|
|
(bool success, bytes memory returndata) = target.call{value: value}(data);
|
|
|
- return verifyCallResult(success, returndata, errorMessage);
|
|
|
+ return verifyCallResultFromTarget(target, success, returndata, errorMessage);
|
|
|
}
|
|
|
|
|
|
/**
|
|
@@ -159,10 +157,8 @@ library Address {
|
|
|
bytes memory data,
|
|
|
string memory errorMessage
|
|
|
) internal view returns (bytes memory) {
|
|
|
- require(isContract(target), "Address: static call to non-contract");
|
|
|
-
|
|
|
(bool success, bytes memory returndata) = target.staticcall(data);
|
|
|
- return verifyCallResult(success, returndata, errorMessage);
|
|
|
+ return verifyCallResultFromTarget(target, success, returndata, errorMessage);
|
|
|
}
|
|
|
|
|
|
/**
|
|
@@ -186,15 +182,37 @@ library Address {
|
|
|
bytes memory data,
|
|
|
string memory errorMessage
|
|
|
) internal returns (bytes memory) {
|
|
|
- require(isContract(target), "Address: delegate call to non-contract");
|
|
|
-
|
|
|
(bool success, bytes memory returndata) = target.delegatecall(data);
|
|
|
- return verifyCallResult(success, returndata, errorMessage);
|
|
|
+ return verifyCallResultFromTarget(target, success, returndata, errorMessage);
|
|
|
+ }
|
|
|
+
|
|
|
+ /**
|
|
|
+ * @dev Tool to verify that a low level call to smart-contract was successful, and revert (either by bubbling
|
|
|
+ * the revert reason or using the provided one) in case of unsuccessful call or if target was not a contract.
|
|
|
+ *
|
|
|
+ * _Available since v4.8._
|
|
|
+ */
|
|
|
+ function verifyCallResultFromTarget(
|
|
|
+ address target,
|
|
|
+ bool success,
|
|
|
+ bytes memory returndata,
|
|
|
+ string memory errorMessage
|
|
|
+ ) internal view returns (bytes memory) {
|
|
|
+ if (success) {
|
|
|
+ if (returndata.length == 0) {
|
|
|
+ // only check isContract if the call was successful and the return data is empty
|
|
|
+ // otherwise we already know that it was a contract
|
|
|
+ require(isContract(target), "Address: call to non-contract");
|
|
|
+ }
|
|
|
+ return returndata;
|
|
|
+ } else {
|
|
|
+ _revert(returndata, errorMessage);
|
|
|
+ }
|
|
|
}
|
|
|
|
|
|
/**
|
|
|
- * @dev Tool to verifies that a low level call was successful, and revert if it wasn't, either by bubbling the
|
|
|
- * revert reason using the provided one.
|
|
|
+ * @dev Tool to verify that a low level call was successful, and revert if it wasn't, either by bubbling the
|
|
|
+ * revert reason or using the provided one.
|
|
|
*
|
|
|
* _Available since v4.3._
|
|
|
*/
|
|
@@ -206,17 +224,21 @@ library Address {
|
|
|
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
|
|
|
- /// @solidity memory-safe-assembly
|
|
|
- assembly {
|
|
|
- let returndata_size := mload(returndata)
|
|
|
- revert(add(32, returndata), returndata_size)
|
|
|
- }
|
|
|
- } else {
|
|
|
- revert(errorMessage);
|
|
|
+ _revert(returndata, errorMessage);
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ function _revert(bytes memory returndata, string memory errorMessage) private pure {
|
|
|
+ // 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
|
|
|
+ /// @solidity memory-safe-assembly
|
|
|
+ assembly {
|
|
|
+ let returndata_size := mload(returndata)
|
|
|
+ revert(add(32, returndata), returndata_size)
|
|
|
}
|
|
|
+ } else {
|
|
|
+ revert(errorMessage);
|
|
|
}
|
|
|
}
|
|
|
}
|