1
+ // SPDX-License-Identifier: MIT
2
+
3
+ pragma solidity >= 0.7.0 < 0.8.0 ;
4
+
5
+ import "./IERC20.sol " ;
6
+ import "./SafeMath.sol " ;
7
+ import "./Address.sol " ;
8
+
9
+ /**
10
+ * @title SafeERC20
11
+ * @dev Wrappers around ERC20 operations that throw on failure (when the token
12
+ * contract returns false). Tokens that return no value (and instead revert or
13
+ * throw on failure) are also supported, non-reverting calls are assumed to be
14
+ * successful.
15
+ * To use this library you can add a `using SafeERC20 for ERC20;` statement to your contract,
16
+ * which allows you to call the safe operations as `token.safeTransfer(...)`, etc.
17
+ */
18
+ library SafeERC20 {
19
+ using SafeMath for uint256 ;
20
+ using Address for address ;
21
+
22
+ function safeTransfer (IERC20 token , address to , uint256 value ) internal {
23
+ _callOptionalReturn (token, abi.encodeWithSelector (token.transfer.selector , to, value));
24
+ }
25
+
26
+ function safeTransferFrom (IERC20 token , address from , address to , uint256 value ) internal {
27
+ _callOptionalReturn (token, abi.encodeWithSelector (token.transferFrom.selector , from, to, value));
28
+ }
29
+
30
+ function safeApprove (IERC20 token , address spender , uint256 value ) internal {
31
+ // safeApprove should only be called when setting an initial allowance,
32
+ // or when resetting it to zero. To increase and decrease it, use
33
+ // 'safeIncreaseAllowance' and 'safeDecreaseAllowance'
34
+ // solhint-disable-next-line max-line-length
35
+ require ((value == 0 ) || (token.allowance (address (this ), spender) == 0 ),
36
+ "SafeERC20: approve from non-zero to non-zero allowance "
37
+ );
38
+ _callOptionalReturn (token, abi.encodeWithSelector (token.approve.selector , spender, value));
39
+ }
40
+
41
+ function safeIncreaseAllowance (IERC20 token , address spender , uint256 value ) internal {
42
+ uint256 newAllowance = token.allowance (address (this ), spender).add (value);
43
+ _callOptionalReturn (token, abi.encodeWithSelector (token.approve.selector , spender, newAllowance));
44
+ }
45
+
46
+ function safeDecreaseAllowance (IERC20 token , address spender , uint256 value ) internal {
47
+ uint256 newAllowance = token.allowance (address (this ), spender).sub (value, "SafeERC20: decreased allowance below zero " );
48
+ _callOptionalReturn (token, abi.encodeWithSelector (token.approve.selector , spender, newAllowance));
49
+ }
50
+
51
+ /**
52
+ * @dev Imitates a Solidity high-level call (i.e. a regular function call to a contract), relaxing the requirement
53
+ * on the return value: the return value is optional (but if data is returned, it must not be false).
54
+ * @param token The token targeted by the call.
55
+ * @param data The call data (encoded using abi.encode or one of its variants).
56
+ */
57
+ function _callOptionalReturn (IERC20 token , bytes memory data ) private {
58
+ // We need to perform a low level call here, to bypass Solidity's return data size checking mechanism, since
59
+ // we're implementing it ourselves.
60
+
61
+ // A Solidity high level call has three parts:
62
+ // 1. The target address is checked to verify it contains contract code
63
+ // 2. The call itself is made, and success asserted
64
+ // 3. The return value is decoded, which in turn checks the size of the returned data.
65
+ // solhint-disable-next-line max-line-length
66
+ require (address (token).isContract (), "SafeERC20: call to non-contract " );
67
+
68
+ // solhint-disable-next-line avoid-low-level-calls
69
+ (bool success , bytes memory returndata ) = address (token).call (data);
70
+ require (success, "SafeERC20: low-level call failed " );
71
+
72
+ if (returndata.length > 0 ) { // Return data is optional
73
+ // solhint-disable-next-line max-line-length
74
+ require (abi.decode (returndata, (bool )), "SafeERC20: ERC20 operation did not succeed " );
75
+ }
76
+ }
77
+ }
0 commit comments