@@ -10,6 +10,9 @@ library AddressUtils {
10
10
error AddressUtils__InsufficientBalance ();
11
11
error AddressUtils__NotContract ();
12
12
error AddressUtils__SendValueFailed ();
13
+ error AddressUtils__FailedCall ();
14
+ error AddressUtils__FailedCallWithValue ();
15
+ error AddressUtils__FailedDelegatecall ();
13
16
14
17
function toString (address account ) internal pure returns (string memory ) {
15
18
return uint256 (uint160 (account)).toHexString (20 );
@@ -32,14 +35,13 @@ library AddressUtils {
32
35
address target ,
33
36
bytes memory data
34
37
) internal returns (bytes memory ) {
35
- return
36
- functionCall (target, data, 'AddressUtils: failed low-level call ' );
38
+ return functionCall (target, data, AddressUtils__FailedCall.selector );
37
39
}
38
40
39
41
function functionCall (
40
42
address target ,
41
43
bytes memory data ,
42
- string memory error
44
+ bytes4 error
43
45
) internal returns (bytes memory ) {
44
46
return _functionCallWithValue (target, data, 0 , error );
45
47
}
@@ -54,21 +56,43 @@ library AddressUtils {
54
56
target,
55
57
data,
56
58
value,
57
- ' AddressUtils: failed low-level call with value '
59
+ AddressUtils__FailedCallWithValue. selector
58
60
);
59
61
}
60
62
61
63
function functionCallWithValue (
62
64
address target ,
63
65
bytes memory data ,
64
66
uint256 value ,
65
- string memory error
67
+ bytes4 error
66
68
) internal returns (bytes memory ) {
67
69
if (value > address (this ).balance)
68
70
revert AddressUtils__InsufficientBalance ();
69
71
return _functionCallWithValue (target, data, value, error );
70
72
}
71
73
74
+ function functionDelegateCall (
75
+ address target ,
76
+ bytes memory data
77
+ ) internal returns (bytes memory ) {
78
+ return
79
+ functionDelegateCall (
80
+ target,
81
+ data,
82
+ AddressUtils__FailedDelegatecall.selector
83
+ );
84
+ }
85
+
86
+ function functionDelegateCall (
87
+ address target ,
88
+ bytes memory data ,
89
+ bytes4 error
90
+ ) internal returns (bytes memory ) {
91
+ (bool success , bytes memory returnData ) = target.delegatecall (data);
92
+ _verifyCallResultFromTarget (target, success, returnData, error );
93
+ return returnData;
94
+ }
95
+
72
96
/**
73
97
* @notice execute arbitrary external call with limited gas usage and amount of copied return data
74
98
* @dev derived from https://github.com/nomad-xyz/ExcessivelySafeCall (MIT License)
@@ -120,23 +144,37 @@ library AddressUtils {
120
144
address target ,
121
145
bytes memory data ,
122
146
uint256 value ,
123
- string memory error
147
+ bytes4 error
124
148
) private returns (bytes memory ) {
125
- if (! isContract (target)) revert AddressUtils__NotContract ();
126
-
127
149
(bool success , bytes memory returnData ) = target.call { value: value }(
128
150
data
129
151
);
152
+ _verifyCallResultFromTarget (target, success, returnData, error );
153
+ return returnData;
154
+ }
130
155
131
- if (success) {
132
- return returnData;
133
- } else if (returnData.length > 0 ) {
134
- assembly {
135
- let returnData_size := mload (returnData)
136
- revert (add (32 , returnData), returnData_size)
156
+ function _verifyCallResultFromTarget (
157
+ address target ,
158
+ bool success ,
159
+ bytes memory returnData ,
160
+ bytes4 error
161
+ ) private view {
162
+ if (! success) {
163
+ if (returnData.length == 0 ) {
164
+ assembly {
165
+ mstore (0 , error )
166
+ revert (0 , 4 )
167
+ }
168
+ } else {
169
+ assembly {
170
+ let returnData_size := mload (returnData)
171
+ revert (add (32 , returnData), returnData_size)
172
+ }
137
173
}
138
- } else {
139
- revert (error );
140
174
}
175
+
176
+ // code check is only required if call is successful and without return data
177
+ if (returnData.length == 0 && ! isContract (target))
178
+ revert AddressUtils__NotContract ();
141
179
}
142
180
}
0 commit comments