1+ // SPDX-License-Identifier: MIT
2+ pragma solidity 0.8.10 ;
3+
4+ /**
5+ * @dev Collection of functions related to the address type
6+ */
7+ library Address {
8+ /**
9+ * @dev Returns true if `account` is a contract.
10+ *
11+ * [IMPORTANT]
12+ * ====
13+ * It is unsafe to assume that an address for which this function returns
14+ * false is an externally-owned account (EOA) and not a contract.
15+ *
16+ * Among others, `isContract` will return false for the following
17+ * types of addresses:
18+ *
19+ * - an externally-owned account
20+ * - a contract in construction
21+ * - an address where a contract will be created
22+ * - an address where a contract lived, but was destroyed
23+ * ====
24+ *
25+ * [IMPORTANT]
26+ * ====
27+ * You shouldn't rely on `isContract` to protect against flash loan attacks!
28+ *
29+ * Preventing calls from contracts is highly discouraged. It breaks composability, breaks support for smart wallets
30+ * like Gnosis Safe, and does not provide security since it can be circumvented by calling from a contract
31+ * constructor.
32+ * ====
33+ */
34+ function isContract (address account ) internal view returns (bool ) {
35+ // This method relies on extcodesize/address.code.length, which returns 0
36+ // for contracts in construction, since the code is only stored at the end
37+ // of the constructor execution.
38+
39+ uint256 size;
40+ // solhint-disable-next-line no-inline-assembly
41+ assembly { size := extcodesize (account) }
42+ return size > 0 ;
43+ }
44+
45+ /**
46+ * @dev Replacement for Solidity's `transfer`: sends `amount` wei to
47+ * `recipient`, forwarding all available gas and reverting on errors.
48+ *
49+ * https://eips.ethereum.org/EIPS/eip-1884[EIP1884] increases the gas cost
50+ * of certain opcodes, possibly making contracts go over the 2300 gas limit
51+ * imposed by `transfer`, making them unable to receive funds via
52+ * `transfer`. {sendValue} removes this limitation.
53+ *
54+ * https://diligence.consensys.net/posts/2019/09/stop-using-soliditys-transfer-now/[Learn more].
55+ *
56+ * IMPORTANT: because control is transferred to `recipient`, care must be
57+ * taken to not create reentrancy vulnerabilities. Consider using
58+ * {ReentrancyGuard} or the
59+ * https://solidity.readthedocs.io/en/v0.5.11/security-considerations.html#use-the-checks-effects-interactions-pattern[checks-effects-interactions pattern].
60+ */
61+ function sendValue (address payable recipient , uint256 amount ) internal {
62+ require (address (this ).balance >= amount, "Address: insufficient balance " );
63+
64+ (bool success , ) = recipient.call {value: amount}("" );
65+ require (success, "Address: unable to send value, recipient may have reverted " );
66+ }
67+
68+ /**
69+ * @dev Performs a Solidity function call using a low level `call`. A
70+ * plain `call` is an unsafe replacement for a function call: use this
71+ * function instead.
72+ *
73+ * If `target` reverts with a revert reason, it is bubbled up by this
74+ * function (like regular Solidity function calls).
75+ *
76+ * Returns the raw returned data. To convert to the expected return value,
77+ * use https://solidity.readthedocs.io/en/latest/units-and-global-variables.html?highlight=abi.decode#abi-encoding-and-decoding-functions[`abi.decode`].
78+ *
79+ * Requirements:
80+ *
81+ * - `target` must be a contract.
82+ * - calling `target` with `data` must not revert.
83+ *
84+ * _Available since v3.1._
85+ */
86+ function functionCall (address target , bytes memory data ) internal returns (bytes memory ) {
87+ return functionCall (target, data, "Address: low-level call failed " );
88+ }
89+
90+ /**
91+ * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`], but with
92+ * `errorMessage` as a fallback revert reason when `target` reverts.
93+ *
94+ * _Available since v3.1._
95+ */
96+ function functionCall (
97+ address target ,
98+ bytes memory data ,
99+ string memory errorMessage
100+ ) internal returns (bytes memory ) {
101+ return functionCallWithValue (target, data, 0 , errorMessage);
102+ }
103+
104+ /**
105+ * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],
106+ * but also transferring `value` wei to `target`.
107+ *
108+ * Requirements:
109+ *
110+ * - the calling contract must have an ETH balance of at least `value`.
111+ * - the called Solidity function must be `payable`.
112+ *
113+ * _Available since v3.1._
114+ */
115+ function functionCallWithValue (
116+ address target ,
117+ bytes memory data ,
118+ uint256 value
119+ ) internal returns (bytes memory ) {
120+ return functionCallWithValue (target, data, value, "Address: low-level call with value failed " );
121+ }
122+
123+ /**
124+ * @dev Same as {xref-Address-functionCallWithValue-address-bytes-uint256-}[`functionCallWithValue`], but
125+ * with `errorMessage` as a fallback revert reason when `target` reverts.
126+ *
127+ * _Available since v3.1._
128+ */
129+ function functionCallWithValue (
130+ address target ,
131+ bytes memory data ,
132+ uint256 value ,
133+ string memory errorMessage
134+ ) internal returns (bytes memory ) {
135+ require (address (this ).balance >= value, "Address: insufficient balance for call " );
136+ require (isContract (target), "Address: call to non-contract " );
137+
138+ (bool success , bytes memory returndata ) = target.call {value: value}(data);
139+ return verifyCallResult (success, returndata, errorMessage);
140+ }
141+
142+ /**
143+ * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],
144+ * but performing a static call.
145+ *
146+ * _Available since v3.3._
147+ */
148+ function functionStaticCall (address target , bytes memory data ) internal view returns (bytes memory ) {
149+ return functionStaticCall (target, data, "Address: low-level static call failed " );
150+ }
151+
152+ /**
153+ * @dev Same as {xref-Address-functionCall-address-bytes-string-}[`functionCall`],
154+ * but performing a static call.
155+ *
156+ * _Available since v3.3._
157+ */
158+ function functionStaticCall (
159+ address target ,
160+ bytes memory data ,
161+ string memory errorMessage
162+ ) internal view returns (bytes memory ) {
163+ require (isContract (target), "Address: static call to non-contract " );
164+
165+ (bool success , bytes memory returndata ) = target.staticcall (data);
166+ return verifyCallResult (success, returndata, errorMessage);
167+ }
168+
169+ /**
170+ * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],
171+ * but performing a delegate call.
172+ *
173+ * _Available since v3.4._
174+ */
175+ function functionDelegateCall (address target , bytes memory data ) internal returns (bytes memory ) {
176+ return functionDelegateCall (target, data, "Address: low-level delegate call failed " );
177+ }
178+
179+ /**
180+ * @dev Same as {xref-Address-functionCall-address-bytes-string-}[`functionCall`],
181+ * but performing a delegate call.
182+ *
183+ * _Available since v3.4._
184+ */
185+ function functionDelegateCall (
186+ address target ,
187+ bytes memory data ,
188+ string memory errorMessage
189+ ) internal returns (bytes memory ) {
190+ require (isContract (target), "Address: delegate call to non-contract " );
191+
192+ (bool success , bytes memory returndata ) = target.delegatecall (data);
193+ return verifyCallResult (success, returndata, errorMessage);
194+ }
195+
196+ /**
197+ * @dev Tool to verifies that a low level call was successful, and revert if it wasn't, either by bubbling the
198+ * revert reason using the provided one.
199+ *
200+ * _Available since v4.3._
201+ */
202+ function verifyCallResult (
203+ bool success ,
204+ bytes memory returndata ,
205+ string memory errorMessage
206+ ) internal pure returns (bytes memory ) {
207+ if (success) {
208+ return returndata;
209+ } else {
210+ // Look for revert reason and bubble it up if present
211+ if (returndata.length > 0 ) {
212+ // The easiest way to bubble the revert reason is using memory via assembly
213+
214+ assembly {
215+ let returndata_size := mload (returndata)
216+ revert (add (32 , returndata), returndata_size)
217+ }
218+ } else {
219+ revert (errorMessage);
220+ }
221+ }
222+ }
223+ }
0 commit comments