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