This standard extends ERC-20 tokens with EIP-165, and adds familiar functions from ERC-721 and ERC-1155 ensuring receiving contracts have implemented proper functionality.
EIP-165 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 and ERC-1155. 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 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 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 and ERC-1155 standards integrating EIP-165. Our hope is that this extension to ERC-20 would also help future extensions by making them easier to integrate.
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:
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
):
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);
}
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.
There are no issues with backwards compatibility in this EIP, as the full suite of ERC-20 functions is unchanged.
Test cases have been provided in the implementation repo here.
A sample repo demonstrating an implementation of this EIP has been created here. It is (as of this writing) in a Dapptools environment, for details on installing and running Dapptools see the Dapptools repo.
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 and related rights waived via CC0.