ERC-4400: EIP-721 Consumable Extension
ERC-4400 is the earlier consumable-NFT pattern that ERC-2135 and ERC-6672 later extended. Each NFT has a single consumer address that can be set by the owner; the consumer is allowed to "consume" the NFT once. Simpler than 2135 (no consumed-flag tracking) and 6672 (no per-operator state).
Common in:
- Single-use voucher NFTs that delegate consumption to a service.
- Event tickets where the venue is the consumer.
- Subscription NFTs delegating period-end actions to a scheduler.
Required Interface
solidity
interface IERC4400 {
event ConsumerChanged(address indexed owner, address indexed consumer, uint256 indexed tokenId);
function changeConsumer(address consumer, uint256 tokenId) external;
function consumerOf(uint256 tokenId) external view returns (address);
}The owner sets a consumer via changeConsumer; the consumer reads the slot via consumerOf. Whether the consumer is reset on transfer or persists is implementation-defined (the OpenZeppelin reference clears it on transfer).
Neo Equivalent: NEP-11 + Per-Token Consumer Slot
csharp
public static void ChangeConsumer(UInt160 consumer, ByteString tokenId)
{
var owner = OwnerOf(tokenId);
if (!Runtime.CheckWitness(owner)) throw new Exception("NEP11:NotOwner");
Storage.Put(Storage.CurrentContext, ConsumerKey(tokenId), consumer);
OnConsumerChanged(owner, consumer, tokenId);
}
public static UInt160 ConsumerOf(ByteString tokenId)
{
var raw = Storage.Get(Storage.CurrentContext, ConsumerKey(tokenId));
return raw is null ? null : (UInt160)raw;
}
// Nep11Token<T> has no virtual hook; use `public new static`.
public new static bool Transfer(UInt160 to, ByteString tokenId, object data = null)
{
var ok = Nep11Token<TokenState>.Transfer(to, tokenId, data);
if (ok) Storage.Delete(Storage.CurrentContext, ConsumerKey(tokenId)); // clear on transfer
return ok;
}| ERC-4400 (Ethereum) | Neo Equivalent | Notes |
|---|---|---|
changeConsumer(consumer, tokenId) | ChangeConsumer(consumer, tokenId) owner-witness-checked | |
consumerOf(tokenId) | ConsumerOf(tokenId) view | |
| Cleared on transfer (OZ ref) | OnTransfer override deletes the slot | Direct port |
Comparison with ERC-2135 and ERC-6672
| Standard | Tracks consumed | Per-operator |
|---|---|---|
| ERC-4400 (this) | No (just authorises a consumer) | One consumer per token |
| ERC-2135 | Yes (binary flag) | One consumer per token |
| ERC-6672 | Yes (per redemptionId) | Multiple operators per token |
Pick ERC-4400 for the simplest "delegate consumption" use case; pick 2135 for single-use vouchers; pick 6672 for multi-event memberships.
