ERC-7432 NFT role assignment standard (Non-Fungible Token Roles)

Final · NFTs & multi-token · created 2023-07-14

Defines a common way to grant another account a role that expires automatically at a set time, while leaving ownership of the NFT unchanged. It can be used to split the utility of an NFT, as in digital real estate rentals or insurance policies.

Why it is needed

An NFT has only one owner, so it is hard to share its utility with others. For example, to hand someone the management or tenancy rights of a digital real estate NFT, the token itself must be transferred, and ownership goes with it. Also, without a common rule for recording on-chain who holds which permission and until when, every decentralized application (dApp) must implement access control for special actions, such as airdrop eligibility, in its own way. ERC-7432 defines a common interface that attaches multiple roles to a single NFT and makes each role expire automatically at a set time. Roles are identified by a bytes32 value and can carry additional data of arbitrary size, so they can be adapted to many uses that lend out only the utility while preserving ownership.

What to implement

In depth

A standalone standard, not an extension of ERC-721

This standard does not inherit from ERC-721. This lets it be implemented in the same contract as the NFT or as a separate external contract. For that reason, every function and event takes both tokenAddress and tokenId. This structure lets a standalone ERC-7432 contract serve as the authoritative source of roles, so role functionality can be added even to NFTs that are already deployed and immutable. A compliant contract must implement the IERC7432 interface, implementing ERC-165 is recommended, and the ERC-165 identifier of this interface is 0xd00ca5cf.

Role identifiers and the Role struct

Roles are identified by a bytes32 value. It is recommended to use the hash of the role name and input type with keccak256, that is, the form keccak256("RoleName(input_type)"). The Role struct passed to grantRole consists of roleId, tokenAddress, tokenId, recipient (the account receiving the role), expirationDate (a uint64 expiration time), revocable (whether early revocation is allowed), and data (additional data of arbitrary size). Because data is of type bytes, an app can freely encode whatever information the role needs. It is returned as is by the roleData function and is also recorded in the RoleGranted event, so it can be used both on-chain and off-chain.

grantRole and token locking

grantRole must revert if expirationDate is in the past or if msg.sender is not an account approved to grant roles on behalf of the NFT owner. When a role is granted, it emits a RoleGranted event, and if the token is frozen or moved to an escrow account, it must also emit a TokenLocked event. The source uses the neutral term lock so as not to prescribe an implementation. It may be a freeze that blocks transfers until the role expires, or it may be a deposit into an escrow contract, and the implementer chooses whichever fits the use case.

Automatic expiration and uint64 dates

Expiration is implemented by the expirationDate that grantRole sets and the roleExpirationDate function that reads it. Dates are represented as uint64 instead of uint256 because most programming languages do not natively support uint256. The maximum Unix timestamp representable in uint64 corresponds to about 584,942,417,355 years, which is effectively permanent. So for uses where a role must never expire, it is recommended to use type(uint64).max.

Revocability and unlockToken

If revocable is true, both the original owner and the recipient can revoke the role with revokeRole before it expires; if false, only the recipient can. So that a recipient can remove an unwanted role on their own, it is recommended to always allow revocation by the recipient regardless of the revocable value. revokeRole must revert if msg.sender is not authorized to act on behalf of the original owner or the recipient. unlockToken returns a locked NFT to its original owner or lifts the freeze, and it must revert if msg.sender is not approved or if any unexpired non-revocable role remains. This rule protects a recipient who was given a non-revocable role.

Role Approval

Similar to ERC-721 approvals, another account can manage roles on behalf of the owner. With setRoleApprovalForAll, an operator can be given or stripped of the authority to grant and revoke roles for a specific token address, and a RoleApprovalForAll event is recorded when the approval state changes. isRoleApprovedForAll must return true only if the operator is approved to grant and revoke roles on behalf of the original NFT owner. This feature was introduced so that third parties who do not own the NFT can interact with ERC-7432, and a compliant contract must implement both functions.

Metadata extension

The optional metadata extension adds a roles array to an existing NFT's JSON metadata. An app that supports this feature must also implement ERC-721's metadata extension. Each role entry contains an id (bytes32) that identifies the role, a human-readable name, a description, and inputs. inputs is an important field that describes the parameters that must be encoded and passed to grantRole, and it is recommended to use the type and components properties defined in the Solidity ABI specification. The property layout of the roles array is only a suggestion, so developers can add other information, such as a role image, as needed.

Things to watch out for

Original ERC · ← ERCs