Wrappers around ERC20 operations that throw on failure (when the token contract returns false). Tokens that return no value (and instead revert or throw on failure) are also supported, non-reverting calls are assumed to be successful. To use this library you can add a using SafeERC20 for IERC20; statement to your contract, which allows you to call the safe operations as token.safeTransfer(…), etc.
OpenZeppelin SafeERC20
Several other "safe" functions are implemented:
safeTransfer() and safeTransferFrom()
safeApprove()
safeIncreaseAllowance() and safeDecreaseAllowance()
safeTransfer() and safeTransferFrom()
/** * @dev Transfer `value` amount of `token` from the calling contract to `to`. If `token` returns no value, * non-reverting calls are assumed to be successful. */functionsafeTransfer(IERC20 token,address to,uint256 value) internal {_callOptionalReturn(token, abi.encodeWithSelector(token.transfer.selector, to, value));}/** * @dev Transfer `value` amount of `token` from `from` to `to`, spending the approval given by `from` to the * calling contract. If `token` returns no value, non-reverting calls are assumed to be successful. */functionsafeTransferFrom(IERC20 token,address from,address to,uint256 value) internal {_callOptionalReturn(token, abi.encodeWithSelector(token.transferFrom.selector, from, to, value));}
/** * @dev Imitates a Solidity high-level call (i.e. a regular function call to a contract), relaxing the requirement * on the return value: the return value is optional (but if data is returned, it must not be false). * @param token The token targeted by the call. * @param data The call data (encoded using abi.encode or one of its variants). */function_callOptionalReturn(IERC20 token,bytesmemory data) private {// We need to perform a low level call here, to bypass Solidity's return data size checking mechanism, since// we're implementing it ourselves. We use {Address-functionCall} to perform this call, which verifies that// the target address contains contract code and also asserts for success in the low-level call.bytesmemory returndata =address(token).functionCall(data,"SafeERC20: low-level call failed");require(returndata.length ==0|| abi.decode(returndata, (bool)),"SafeERC20: ERC20 operation did not succeed");}
safeApprove()
/** * @dev Deprecated. This function has issues similar to the ones found in * {IERC20-approve}, and its usage is discouraged. * * Whenever possible, use {safeIncreaseAllowance} and * {safeDecreaseAllowance} instead. */functionsafeApprove(IERC20 token,address spender,uint256 value) internal {// safeApprove should only be called when setting an initial allowance,// or when resetting it to zero. To increase and decrease it, use// 'safeIncreaseAllowance' and 'safeDecreaseAllowance'require( (value ==0) || (token.allowance(address(this), spender) ==0),"SafeERC20: approve from non-zero to non-zero allowance" );_callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, value));}
Read this comment:
// safeApprove should only be called when setting an initial allowance,// or when resetting it to zero. To increase and decrease it, use// 'safeIncreaseAllowance' and 'safeDecreaseAllowance'
safeIncreaseAllowance() and safeDecreaseAllowance()
/** * @dev Increase the calling contract's allowance toward `spender` by `value`. If `token` returns no value, * non-reverting calls are assumed to be successful. */functionsafeIncreaseAllowance(IERC20 token,address spender,uint256 value) internal {uint256 oldAllowance = token.allowance(address(this), spender);_callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, oldAllowance + value));}/** * @dev Decrease the calling contract's allowance toward `spender` by `value`. If `token` returns no value, * non-reverting calls are assumed to be successful. */functionsafeDecreaseAllowance(IERC20 token,address spender,uint256 value) internal {unchecked {uint256 oldAllowance = token.allowance(address(this), spender);require(oldAllowance >= value,"SafeERC20: decreased allowance below zero");_callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, oldAllowance - value)); }}