4
4
pragma solidity ^ 0.8.20 ;
5
5
6
6
import {Errors} from "./Errors.sol " ;
7
+ import {LowLevelCall} from "./LowLevelCall.sol " ;
7
8
8
9
/**
9
10
* @dev Collection of functions related to the address type
@@ -34,10 +35,13 @@ library Address {
34
35
if (address (this ).balance < amount) {
35
36
revert Errors.InsufficientBalance (address (this ).balance, amount);
36
37
}
37
-
38
- (bool success , bytes memory returndata ) = recipient.call {value: amount}("" );
39
- if (! success) {
40
- _revert (returndata);
38
+ if (LowLevelCall.callNoReturn (recipient, amount, "" )) {
39
+ // call successful, nothing to do
40
+ return ;
41
+ } else if (LowLevelCall.returnDataSize () > 0 ) {
42
+ LowLevelCall.bubbleRevert ();
43
+ } else {
44
+ revert Errors.FailedCall ();
41
45
}
42
46
}
43
47
@@ -76,47 +80,74 @@ library Address {
76
80
if (address (this ).balance < value) {
77
81
revert Errors.InsufficientBalance (address (this ).balance, value);
78
82
}
79
- (bool success , bytes memory returndata ) = target.call {value: value}(data);
80
- return verifyCallResultFromTarget (target, success, returndata);
83
+ bool success = LowLevelCall.callNoReturn (target, value, data);
84
+ if (success && (LowLevelCall.returnDataSize () > 0 || target.code.length > 0 )) {
85
+ return LowLevelCall.returnData ();
86
+ } else if (success) {
87
+ revert AddressEmptyCode (target);
88
+ } else if (LowLevelCall.returnDataSize () > 0 ) {
89
+ LowLevelCall.bubbleRevert ();
90
+ } else {
91
+ revert Errors.FailedCall ();
92
+ }
81
93
}
82
94
83
95
/**
84
96
* @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],
85
97
* but performing a static call.
86
98
*/
87
99
function functionStaticCall (address target , bytes memory data ) internal view returns (bytes memory ) {
88
- (bool success , bytes memory returndata ) = target.staticcall (data);
89
- return verifyCallResultFromTarget (target, success, returndata);
100
+ bool success = LowLevelCall.staticcallNoReturn (target, data);
101
+ if (success && (LowLevelCall.returnDataSize () > 0 || target.code.length > 0 )) {
102
+ return LowLevelCall.returnData ();
103
+ } else if (success) {
104
+ revert AddressEmptyCode (target);
105
+ } else if (LowLevelCall.returnDataSize () > 0 ) {
106
+ LowLevelCall.bubbleRevert ();
107
+ } else {
108
+ revert Errors.FailedCall ();
109
+ }
90
110
}
91
111
92
112
/**
93
113
* @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],
94
114
* but performing a delegate call.
95
115
*/
96
116
function functionDelegateCall (address target , bytes memory data ) internal returns (bytes memory ) {
97
- (bool success , bytes memory returndata ) = target.delegatecall (data);
98
- return verifyCallResultFromTarget (target, success, returndata);
117
+ bool success = LowLevelCall.delegatecallNoReturn (target, data);
118
+ if (success && (LowLevelCall.returnDataSize () > 0 || target.code.length > 0 )) {
119
+ return LowLevelCall.returnData ();
120
+ } else if (success) {
121
+ revert AddressEmptyCode (target);
122
+ } else if (LowLevelCall.returnDataSize () > 0 ) {
123
+ LowLevelCall.bubbleRevert ();
124
+ } else {
125
+ revert Errors.FailedCall ();
126
+ }
99
127
}
100
128
101
129
/**
102
130
* @dev Tool to verify that a low level call to smart-contract was successful, and reverts if the target
103
131
* was not a contract or bubbling up the revert reason (falling back to {Errors.FailedCall}) in case
104
132
* of an unsuccessful call.
133
+ *
134
+ * NOTE: This function is DEPRECATED and may be removed in the next major release.
105
135
*/
106
136
function verifyCallResultFromTarget (
107
137
address target ,
108
138
bool success ,
109
139
bytes memory returndata
110
140
) internal view returns (bytes memory ) {
111
- if (! success) {
112
- _revert (returndata);
113
- } else {
114
- // only check if target is a contract if the call was successful and the return data is empty
115
- // otherwise we already know that it was a contract
116
- if (returndata.length == 0 && target.code.length == 0 ) {
117
- revert AddressEmptyCode (target);
118
- }
141
+ // only check if target is a contract if the call was successful and the return data is empty
142
+ // otherwise we already know that it was a contract
143
+ if (success && (returndata.length > 0 || target.code.length > 0 )) {
119
144
return returndata;
145
+ } else if (success) {
146
+ revert AddressEmptyCode (target);
147
+ } else if (returndata.length > 0 ) {
148
+ LowLevelCall.bubbleRevert (returndata);
149
+ } else {
150
+ revert Errors.FailedCall ();
120
151
}
121
152
}
122
153
@@ -125,23 +156,10 @@ library Address {
125
156
* revert reason or with a default {Errors.FailedCall} error.
126
157
*/
127
158
function verifyCallResult (bool success , bytes memory returndata ) internal pure returns (bytes memory ) {
128
- if (! success) {
129
- _revert (returndata);
130
- } else {
159
+ if (success) {
131
160
return returndata;
132
- }
133
- }
134
-
135
- /**
136
- * @dev Reverts with returndata if present. Otherwise reverts with {Errors.FailedCall}.
137
- */
138
- function _revert (bytes memory returndata ) private pure {
139
- // Look for revert reason and bubble it up if present
140
- if (returndata.length > 0 ) {
141
- // The easiest way to bubble the revert reason is using memory via assembly
142
- assembly ("memory-safe" ) {
143
- revert (add (returndata, 0x20 ), mload (returndata))
144
- }
161
+ } else if (returndata.length > 0 ) {
162
+ LowLevelCall.bubbleRevert (returndata);
145
163
} else {
146
164
revert Errors.FailedCall ();
147
165
}
0 commit comments