ERC-6454 Interface for identifying transferable NFTs (Minimal Transferable NFT detection interface)
Final · NFTs & multi-token · created 2023-01-31
Defines a minimal standard function that lets you ask the contract directly whether an NFT can currently be transferred. With it, you can create and identify NFTs that are bound to a specific account and cannot be traded.
Why it is needed
NFTs (non-fungible tokens) are also used for purposes that lose their meaning when the owner changes, such as proof of achievement or a game character's skill. For example, if an NFT that proves an exercise result or a donation could be traded freely, there would be no way to trust that the holder actually did the work. Without a standard, however, there is no way to know in advance from outside which NFTs are non-transferable. A wallet or marketplace has to attempt the transfer and see it fail, which makes the transaction fail and wastes gas (the fee). Guessing whether it will fail by simulating the gas calculation gives a poor user experience. This standard provides a common way to check transferability in advance with a single function.
What to implement
function isTransferable(uint256 tokenId, address from, address to) external view returns (bool);: Reports as true or false whether a given token can be transferred from the from address to the to address. If it returns false, that transfer must fail (revert).
In depth
The isTransferable function and the transfer-blocking rule
The interface consists of a single function, isTransferable(uint256 tokenId, address from, address to), and its ERC-165 identifier is 0x91a6262f. If this function returns false, a transfer of that token MUST revert. If a tokenId that does not exist is passed, the call MUST revert, except when checking whether minting is possible. In other words, it is not a simple lookup function but an enforced rule: the return value must match actual transfer behavior.
How to query general transferability
To check whether a token is transferable in general, callers SHOULD call it with the address 0x0000000000000000000000000000000000000000 for both the from and to parameters. If general transferability is false, every kind of transfer except minting and burning MUST revert. The initial proposal had a simple method that took only tokenId, but discussion pointed out that a token can become non-transferable depending on conditions, so parameters were added and the original function was preserved by passing the zero address.
Telling minting and burning apart, and the exceptions
To check whether minting (issuance) is possible, from MUST be the zero address and to MUST be a non-zero value, and in this case a tokenId that does not yet exist SHOULD be allowed as an exception. To check whether burning is possible, conversely, pass a non-zero value for from and the zero address for to. A token's general transferability MUST NOT be affected by whether it can be minted (from is the zero address) or burned (to is the zero address). This means that even when transfers are blocked, issuance and burning can be handled separately.
Approval checking through the from parameter is optional
Implementers MAY also verify token transfer approval through the from parameter, but this proposal does not require it, so callers SHOULD NOT rely on that behavior. In an implementation that verifies approval, from refers to the transaction initiator (the owner or an operator granted transfer permission), not the owner who sends the token. Approval checking is not mandated because approval is already standardized separately, and forcing an additional check would raise gas consumption.
A minimal design without events or admin functions
This standard has no event announcing that a token has become non-transferable. A token can become non-transferable at creation, at a separate marking time, or when certain conditions are met, and in some cases, such as when it is determined by block number, no event can be emitted. Admin functions that toggle transferability are also deliberately left out of the specification. This keeps to the goal of a general-purpose, minimal proposal and allows a variety of custom implementations. The design direction of this standard is to provide only the minimum interface a non-transferable NFT needs, with fewer methods than comparable existing proposals.
Why a single method was standardized, and compatibility
Overriding the transfer functions is enough to block transfers, but the only way to guarantee non-transferability before contract execution is to have a standard interface. With it, other smart contracts can avoid attempting transfers of non-transferable tokens and suffering transaction failures and wasted gas. Without a standard interface, the only option is to attempt a gas estimation and see whether it reverts, which is a poor user experience. This standard is fully compatible with ERC-721 and existing ERC-721 tooling and infrastructure, and its status is finalized as Final.
Things to watch out for
- Contracts that return false values: A contract may implement the interface but deceive callers, for example by having isTransferable return false for a token that is actually transferable. As with fraudulent ERC-20 and ERC-721 contracts, the existence of such contracts cannot be prevented, so you must verify every external contract you interact with and not interact with untrusted contracts.
- Transferability can change: The transferability state can change over time. Therefore dapps, marketplaces, and wallets that implement this interface must check a token's state each time they display it.
- Hidden logic and unaudited contracts: The same security considerations as ERC-721 apply. Any function, including burning, adding assets, and accepting assets, may contain hidden logic, so take care when dealing with unaudited contracts.