ERC-5380 ERC-721 entitlement extension
Final · NFTs & multi-token · created 2022-03-11
A standard that lets the owner of an NFT (ERC-721) grant another address the right to use certain attributes of that token without transferring the token.
Why it is needed
An NFT has only one owner, so the only way to share the utility a token provides with someone else was to send the token itself. For example, in an on-chain trading card game (TCG), even if someone wanted to use a card only in the game without buying it, there was no standardized way to permit that. The needs also differ by the nature of the right. Some attributes, like a game card, can be used by only one person at a time, while others, like a media usage right, need not be as scarce as the token and can be given to several people. This standard defines a common interface that sets how many people can be granted rights per token and lets the owner distribute entitlements to any addresses they choose.
What to implement
event EntitlementChanged(address indexed user, address indexed contract, uint256 indexed tokenId);: An event emitted when the entitlement amount held by a user changes. If user is the zero address, it means the owner themselves.function entitle(address user, address contract, uint256 tokenId) external;: When the caller is the owner of the ERC-721 token, grants the entitlement for that token to the specified user.function maxEntitlements(address contract, uint256 tokenId) external view (uint256 max);: Queries the maximum number of users that can receive entitlements for that token.function entitlementOf(address user, address contract, uint256 tokenId) external view returns (uint256 amt);: Queries the entitlement amount a specific user holds for that contract and tokenId.function entitlementOfUserByIndex(address user, uint256 index) external view returns (address contract, uint256 tokenId);: Enumerates, one by one by index, the holdings of a user who has at least one entitlement.function tokenURI() external view returns (string);: Returns the token metadata URI in the ERC-1046 format.
In depth
The base interface and how entitle behaves
An entitlement contract that follows the standard MUST implement the ERC5380Entitlement interface. entitle(user, contract, tokenId) grants the entitlement to the specified user when msg.sender is the owner of that ERC-721 token. Note, however, that there is a recommendation (SHOULD NOT) that the call must not revert when it is made by an address that is not the owner. In other words, the design treats a failure as a silent no-op rather than an exception.
Defaults of maxEntitlements and entitlementOf
maxEntitlements(contract, tokenId) returns the maximum number of users that can receive entitlements for that token. This value distinguishes attributes that only one person may use at a time, such as a game card, from attributes that may be given to several people. entitlementOf(user, contract, tokenId) returns the entitlement amount (amt) of a specific user, and by default the full maxEntitlements(contract, tokenId) is assigned to contract.ownerOf(tokenId), that is, the token owner. This means that if the token has not been lent to anyone, all rights belong to the owner.
EntitlementChanged event
When the entitlement amount held by a user changes, the EntitlementChanged(user, contract, tokenId) event is emitted. All three arguments, user, contract and tokenId, are indexed, which makes log filtering easy. The source text states that if user is the zero address, that user refers to the owner.
ERC-165 interface detection
This standard requires ERC-165. supportsInterface must return true when called with the interface ID of ERC5380Entitlement. The optional extensions ERC5380EntitlementEnumerable and ERC5380EntitlementMetadata have the same requirement for their own interface IDs, so a caller can check on-chain in advance which features are implemented.
Enumerable extension
This is an OPTIONAL but RECOMMENDED extension. entitlementOfUserByIndex(user, index) enumerates, per user, the tokens for which the user holds a nonzero entitlement by incrementing the index, and returns which (contract, tokenId) combination the user holds rights to. It throws if the index is out of range or if user is the zero address.
Metadata extension and the ERC-1046 schema
This is also an optional but recommended extension, and it provides an ERC-1046 compatible tokenURI(). The interop field of the metadata that the URI points to contains an erc5380 entry, which must be set to true for ERC-5380 token metadata and omitted otherwise. This marker signals that a wallet should treat the address as an ERC-5380 entitlement. The metadata may optionally contain name, symbol, description, images and icons. For bitmap images, a width of 320 to 1080 pixels is recommended, and images should have an aspect ratio between 1.91:1 and 4:5. icons must have an aspect ratio of exactly 1:1 and use a transparent background, and if they are bitmaps the height must equal the width.
Why ERC-20 and ERC-1155 are not supported
This standard is for ERC-721 only. According to the Rationale section of the source text, ERC-20 and ERC-1155 are not supported because partial ownership is much more complex to track than boolean ownership, which only considers whether something is owned. For reference, this standard was discussed as an alternative design to ERC-4907 (the rental standard), and its status was finalized as Final.
Things to watch out for
- Inheriting the security considerations of the base standards: The source text states that the security considerations of ERC-721 and ERC-1046 apply as they are. When implementing or integrating an entitlement contract, the cautions of both standards should be reviewed together.