--- eip: 4524 title: Safer ERC-20 description: Extending ERC-20 with ERC165 and adding safeTransfer (like ERC-721 and ERC-1155) author: William Schwab (@wschwab) discussions-to: https://ethereum-magicians.org/t/why-isnt-there-an-erc-for-safetransfer-for-erc20/7604 status: Stagnant type: Standards Track category: ERC created: 2021-12-05 requires: 20, 165 --- ## Abstract This standard extends [ERC-20](./eip-20.md) tokens with [EIP-165](./eip-165.md), and adds familiar functions from [ERC-721](./eip-721.md) and [ERC-1155](./eip-1155.md) ensuring receiving contracts have implemented proper functionality. ## Motivation [EIP-165](./eip-165.md) adds (among other things) the ability to tell if a target recipient explicitly signals compatibility with an ERC. This is already used in the EIPs for NFTs, [ERC-721](./eip-721.md) and [ERC-1155](./eip-1155.md). In addition, EIP-165 is a valuable building block for extensions on popular standards to signal implementation, a trend we've seen in a number of NFT extensions. This EIP aims to bring these innovations back to ERC-20. The importance of [EIP-165](./eip-165.md) is perhaps felt most for app developers looking to integrate with a generic standard such as ERC-20 or ERC-721, while integrating newer innovations built atop these standards. An easy example would be token permits, which allow for a one-transaction approval and transfer. This has already been implemented in many popular ERC-20 tokens using the [ERC-2612](./eip-2612.md) standard or similar. A platform integrating ERC-20 tokens has no easy way of telling if a particular token has implemented token permits or not. (As of this writing, ERC-2612 does not require EIP-165.) With EIP-165, the app (or contracts) could query `supportsInterface` to see if the `interfaceId` of a particular EIP is registered (in this case, EIP-2612), allowing for easier and more modular functions interacting with ERC-20 contracts. It is already common in NFT extensions to include an EIP-165 interface with a standard, we would argue this is at least in part due to the underlying [ERC-721](./eip-721.md) and [ERC-1155](./eip-1155.md) standards integrating EIP-165. Our hope is that this extension to ERC-20 would also help future extensions by making them easier to integrate. ## Specification The key words “MUST”, “MUST NOT”, “REQUIRED”, “SHALL”, “SHALL NOT”, “SHOULD”, “SHOULD NOT”, “RECOMMENDED”, “MAY”, and “OPTIONAL” in this document are to be interpreted as described in RFC 2119. In order to be compliant with this EIP, and ERC-20-compliant contract MUST also implement the following functions: ```solidity pragma solidity 0.8.10; import './IERC20.sol'; import './IERC165.sol'; // the EIP-165 interfaceId for this interface is 0x534f5876 interface SaferERC-20 is IERC20, IERC165 { function safeTransfer(address to, uint256 amount) external returns(bool); function safeTransfer(address to, uint256 amount, bytes memory data) external returns(bool); function safeTransferFrom(address from, address to, uint256 amount) external returns(bool); function safeTransferFrom(address from, address to, uint256 amount, bytes memory data) external returns(bool); } ``` `safeTransfer` and `safeTransferFrom` MUST transfer as expected to EOA addresses, and to contracts implementing `ERC20Receiver` and returning the function selector (`0x4fc35859`) when called, and MUST revert when transferring to a contract which either does not have `ERC20Receiver` implemented, or does not return the function selector when called. In addition, a contract accepting safe transfers MUST implement the following if it wishes to accept safe transfers, and MUST return the function selector (`0x4fc35859`): ```solidity pragma solidity 0.8.10; import './IERC165.sol'; interface ERC20Receiver is IERC165 { function onERC20Received( address _operator, address _from, uint256 _amount, bytes _data ) external returns(bytes4); } ``` ## Rationale This EIP is meant to be minimal and straightforward. Adding EIP-165 to ERC-20 is useful for a number of applications, and outside of a minimal amount of code increasing contract size, carries no downside. The `safeTransfer` and `safeTransferFrom` functions are well recognized from ERC-721 and ERC-1155, and therefore keeping identical naming conventions is reasonable, and the benefits of being able to check for implementation before transferring are as useful for ERC-20 tokens as they are for ERC-721 and ERC-1155. Another easy backport from EIP721 and EIP1155 might be the inclusion of a metadata URI for tokens, allowing them to easily reference logo and other details. This has not been included, both in order to keep this EIP as minimal as possible, and because it is already sufficiently covered by [EIP-1046](./eip-1046.md). ## Backwards Compatibility There are no issues with backwards compatibility in this EIP, as the full suite of ERC-20 functions is unchanged. ## Test Cases Test cases have been provided in the implementation repo [here](https://github.com/wschwab/SaferERC-20/blob/main/src/SaferERC-20.t.sol). ## Reference Implementation A sample repo demonstrating an implementation of this EIP has been created [here](https://github.com/wschwab/SaferERC-20). It is (as of this writing) in a Dapptools environment, for details on installing and running Dapptools see the Dapptools repo. ## Security Considerations `onERC20Received` is a callback function. Callback functions have been exploited in the past as a reentrancy vector, and care should be taken to make sure implementations are not vulnerable. ## Copyright Copyright and related rights waived via [CC0](../LICENSE.md).