Standards
ERC7765 Privileged Non-Fungible Tokens Tied To RWA
A guide to ERC7765 NFTs offering privileged ownership, compliance-gated transfers, and secure real-world asset representation.
ERC7765 is an extension of ERC721 designed for NFTs that represent real-world assets and come with built-in privileges, such as redemption rights, physical delivery, or off-chain access. The standard defines a consistent way for holders to initiate the exercise of these privileges on-chain, making it easier to connect blockchain actions with real-world fulfillment through oracles, custodians, or service providers. Since it inherits ERC721’s transfer and approval logic as-is, ERC7765 focuses specifically on managing privileges, tracking whether a right is still exercisable, enabling exercises on behalf of a beneficiary, and emitting events that off-chain systems can trust.
The motivation comes from a key limitation in ERC721: while NFTs can represent things like tokenized art, property titles, or physical collectibles, there is no unified way to exercise the attached real-world rights. This forces every project to create custom interfaces, fragmenting integrations across wallets and platforms. ERC7765 solves this by offering a standard interface that lets users trigger redemptions, deliveries, or other rights without relying on proprietary contract logic, improving interoperability for wallets, front ends, and even DeFi systems.
The standard builds on ERC721 and ERC165, with optional support for ERC721 Metadata. In RWA ecosystems, ERC7765 often works alongside ERC3643 for compliant transfers or ERC7518 for partitioned, rights-aware structures. It’s already being explored by platforms like MintChain for tokenized collectibles, real estate NFTs, and other assets that pair ownership with redeemable, real-world utility.
Use of ERC7765 in RWA Contexts
ERC7765 lets NFT-based RWAs carry privileges that can actually be used, not just represented. Holders can trigger off-chain actions such as redeeming physical goods, claiming yield, or initiating delivery, while every step remains verifiable on-chain. When exercisePrivilege is called, the contract emits events that custodians, oracles, and fulfillment systems can respond to, creating a bridge between blockchain ownership and real-world execution without relying on private, opaque integrations.
Key Applications in RWA Development
Redemption and Fulfillment Triggers For tokenized physical assets like collectibles, gold, or wine, the holder calls exercisePrivilege to start delivery or redemption. The PrivilegeExercised event becomes the signal that fulfillment agents use to process shipping, settlement, or payouts.
Rights Management in Fractional RWAs When fractional ownership is modeled through NFTs, attached privileges such as voting, yield access, gallery admission, or rental revenue can be exercised by the holder or a delegate. This pairs well with DAO-based decision systems, allowing real estate or art token holders to act in governance.
Access and Yield Claims In fund-based RWAs, privileges can represent access to data rooms, quarterly reports, or claiming distributions. Interfaces like isExercisable help front ends display when rights are available, and pairing with ERC7540 enables delayed or asynchronous settlements when the fulfillment needs time.
Compliance-Gated Privileges Privileges can be linked to identity or jurisdiction checks. If combined with ERC3643, the privilege can only be used when the recipient is verified, supporting regulated redemption or settlement processes for securities.
Developer Advantages in RWA Builds
Interoperable Privilege Layer Because the privilege logic is standardized, wallets, custodians, and oracle systems can integrate without custom handlers. The existing ERC721 transfer logic stays untouched while events create a reliable off-chain bridge.
Flexible Beneficiaries Developers can direct privilege execution to another address, allowing institutions to redeem or vote on behalf of clients, which improves UX in delegated RWA ownership models.
Extensibility Through Data Fields Custom data payloads can carry proofs, signatures, or instructions, making it suitable for cross-chain fulfillment, L2 deployments, and oracle-based verification.
Lightweight for Front Ends View functions like isExercisable make it easy to simulate redemption or fulfillment states for marketplaces and dashboard UIs without heavy gas usage.
The following sequence diagram illustrates exercising a privilege in an RWA NFT (e.g., redeeming physical gold), from holder initiation to off-chain fulfillment. It highlights the beneficiary model and event-driven verification.
Core Specification
ERC7765 NFTs must implement the complete ERC721 interface, including transfers and approvals, without modifying any of those mechanics. On top of that, the standard introduces privilege functions that attach real-world or utility rights to individual NFTs. Each privilege is scoped by both tokenId and privilegeId, and the contract tracks whether a given privilege is still available or has already been used. Any attempt to exercise a privilege that is invalid or no longer available will revert. View functions may revert on invalid identifiers, but otherwise return simple boolean states.
Key definitions:
- Privilege: A right associated with an NFT, defined by a
privilegeId. Examples include redemption rights, access passes, claimable rewards, or delivery triggers. - Exercisable: Indicates that the privilege is currently valid for a specific beneficiary and has not expired or been fully used.
- Exercised: Indicates that the privilege has already been used by that beneficiary, either once or up to the allowed maximum, depending on implementation rules.
- Operator: The caller executing the privilege. This can be the holder or someone approved to act on their behalf under standard ERC721 permissions.
- _data: A flexible field for passing extra information such as proofs, instructions, signatures, or parameters used by fulfillment systems.
The standard optionally supports IERC7765Metadata, which defines how privilege information is exposed through URIs. These URIs typically follow a JSON schema including fields like name, description, and reference to the underlying benefit or redemption resource.
The standard mandates IERC7765 (extending IERC721/IERC165 implicitly). Below is the full ABI-compliant interface from the EIP, with developer notes on RWA relevance.
1// SPDX-License-Identifier: CC0-1.0
2pragma solidity >=0.7.0 <0.9.0;
3
4import "@openzeppelin/contracts/token/ERC721/IERC721.sol";
5import "@openzeppelin/contracts/utils/introspection/IERC165.sol";
6
7/// @title ERC7765 Privileged Non-Fungible Tokens Tied To Real World Assets
8/// @dev See https://eips.ethereum.org/EIPS/eip-7765
9interface IERC7765 is IERC721, IERC165 {
10 // Events
11 /// @notice Emitted when a specific privilege of a token is successfully exercised.
12 /// @param _operator The address that exercised the privilege.
13 /// @param _to The address that benefits from the privilege.
14 /// @param _tokenId The NFT token ID.
15 /// @param _privilegeId The ID of the privilege exercised.
16 event PrivilegeExercised(
17 address indexed _operator,
18 address indexed _to,
19 uint256 indexed _tokenId,
20 uint256 _privilegeId
21 );
22
23 // Functions
24 /// @notice Exercises a specific privilege of a token.
25 /// @dev Reverts if `_privilegeId` is invalid.
26 /// @param _to The address that benefits from the privilege.
27 /// @param _tokenId The NFT token ID.
28 /// @param _privilegeId The ID of the privilege to exercise.
29 /// @param _data Extra data for message or future extension.
30 function exercisePrivilege(
31 address _to,
32 uint256 _tokenId,
33 uint256 _privilegeId,
34 bytes calldata _data
35 ) external;
36
37 /// @notice Checks if a specific privilege can be exercised.
38 /// @dev Reverts if `_privilegeId` is invalid.
39 /// @param _to The address that would benefit.
40 /// @param _tokenId The NFT token ID.
41 /// @param _privilegeId The privilege ID.
42 /// @return _exercisable True if the privilege is exercisable.
43 function isExercisable(
44 address _to,
45 uint256 _tokenId,
46 uint256 _privilegeId
47 ) external view returns (bool _exercisable);
48
49 /// @notice Checks if a specific privilege has been exercised.
50 /// @dev Reverts if `_privilegeId` is invalid.
51 /// @param _to The address that benefited.
52 /// @param _tokenId The NFT token ID.
53 /// @param _privilegeId The privilege ID.
54 /// @return _exercised True if the privilege has been exercised.
55 function isExercised(
56 address _to,
57 uint256 _tokenId,
58 uint256 _privilegeId
59 ) external view returns (bool _exercised);
60
61 /// @notice Lists all privilege IDs associated with a token.
62 /// @param _tokenId The NFT token ID.
63 /// @return privilegeIds An array of privilege IDs.
64 function getPrivilegeIds(
65 uint256 _tokenId
66 ) external view returns (uint256[] memory privilegeIds);
67}IERC7765Metadata
1/// @title ERC7765 Privileged Non-Fungible Tokens Tied To Real World Assets, optional metadata extension
2/// @dev See https://eips.ethereum.org/EIPS/eip-7765
3interface IERC7765Metadata is IERC7765 {
4 /// @notice Returns a URI for metadata about a specific privilege.
5 /// @dev Reverts if `_privilegeId` is invalid. The URI may point to a JSON file conforming to the ERC7765 Metadata JSON Schema.
6 /// @param _privilegeId The privilege ID.
7 /// @return A URI string.
8 function privilegeURI(uint256 _privilegeId) external view returns (string memory);
9}Detailed Function Breakdown
exercisePrivilege(address _to, uint256 _tokenId, uint256 _privilegeId, bytes calldata _data) Calls the privilege tied to an NFT if isExercisable returns true. Once executed, the privilege is marked as used, and the contract emits PrivilegeExercised. The caller must be the NFT owner or an approved operator under normal ERC721 rules. In RWA systems, this typically serves as the on-chain trigger for redemption or settlement events, where _data carries signed instructions, proofs, or oracle payloads. Edge case: the function reverts if the privilege does not exist or if the implementation restricts it to a one-time use.
isExercisable(address _to, uint256 _tokenId, uint256 _privilegeId) Returns whether the privilege is still available for the specified beneficiary, taking into account expiry, quotas, or lock conditions. It reverts if the privilege ID is not valid. In RWA usage, this is the primary check that front ends use before enabling redemption buttons, and can be extended to require KYC or accreditation verification.
isExercised(address _to, uint256 _tokenId, uint256 _privilegeId) Shows whether a privilege has already been used by a given beneficiary and reverts if the privilege ID is invalid. For RWAs, this acts as a clean audit log preventing duplicate redemptions or repeated claims, especially when tied to yield or access events.
getPrivilegeIds(uint256 _tokenId) Returns the full set of privilege identifiers linked to a specific NFT. In practice, RWA marketplaces use this to display available redemption routes, delivery options, or access utilities without custom indexing logic.
privilegeURI(uint256 _privilegeId) (Optional metadata extension) Provides a URI that points to structured privilege information such as name, description, and fulfillment resource. It reverts if the ID does not exist. For RWAs, issuers commonly use IPFS or hosted URIs to store redemption instructions, delivery rules, or legal disclosures tied to a privilege.
Reference Implementation
A reference Solidity implementation is provided in the EIP assets: ERC7765Example.sol. It extends OpenZeppelin's ERC721 with mappings for privileges (mapping(uint256 => mapping(uint256 => mapping(address => bool))) exercised;), fixed privilege lists, and basic access (owner-only exercises).
1import "@openzeppelin/contracts/token/ERC721/ERC721.sol";
2import "@openzeppelin/contracts/utils/introspection/ERC165.sol";
3import "./IERC7765.sol";
4
5contract ERC7765Example is ERC721, ERC165, IERC7765 {
6 mapping(uint256 => uint256[]) private _privilegeIds; // Per tokenId
7 mapping(uint256 => mapping(uint256 => mapping(address => bool))) public exercised; // tokenId -> privilegeId -> to -> exercised
8 mapping(uint256 => bool) public exercisable; // Global per privilegeId (simplified)
9
10 constructor(string memory name, string memory symbol) ERC721(name, symbol) {}
11
12 function supportsInterface(bytes4 interfaceId) public view virtual override(ERC721, IERC165) returns (bool) {
13 return super.supportsInterface(interfaceId) || interfaceId == type(IERC7765).interfaceId;
14 }
15
16 // Init privileges for a token (admin call)
17 function setPrivileges(uint256 tokenId, uint256[] memory ids, bool[] memory canExercise) external onlyOwner {
18 for (uint i = 0; i < ids.length; i++) {
19 _privilegeIds[tokenId].push(ids[i]);
20 exercisable[ids[i]] = canExercise[i];
21 }
22 }
23}This setup attaches privileges to a newly minted NFT and allows admins to define which ones are active. In a full RWA system, this function is typically expanded to support time-based unlock conditions, proof-based activation, or metadata mapping.
Key Functions
exercisePrivilege
1function exercisePrivilege(address _to, uint256 _tokenId, uint256 _privilegeId, bytes calldata _data) external override {
2 require(ownerOf(_tokenId) == msg.sender || isApprovedForAll(ownerOf(_tokenId), msg.sender), "Not owner/operator");
3 require(exercisable[_privilegeId], "Not exercisable");
4 require(!exercised[_tokenId][_privilegeId][_to], "Already exercised");
5 exercised[_tokenId][_privilegeId][_to] = true;
6 emit PrivilegeExercised(msg.sender, _to, _tokenId, _privilegeId);
7 // Impl: Trigger oracle via _data
8}This function allows the holder or their approved operator to execute a privilege, marks it as used, and emits the corresponding event. In RWA flows, _data is typically parsed to carry redemption proofs or fulfillment instructions sent to an oracle.
isExercisable
1function isExercisable(address _to, uint256 _tokenId, uint256 _privilegeId) external view override returns (bool) {
2 // Check in _privilegeIds[tokenId]
3 require(exercisable[_privilegeId], "Invalid privilege"); // Revert on invalid
4 return exercisable[_privilegeId] && !exercised[_tokenId][_privilegeId][_to];
5}This view reports whether the privilege is still valid for the given beneficiary. In production RWA deployments, this logic is typically extended with expiry timestamps, quota counters, or identity checks.
getPrivilegeIds
1function getPrivilegeIds(uint256 _tokenId) external view override returns (uint256[] memory) {
2 return _privilegeIds[_tokenId];
3}This provides a simple list of all privileges attached to a particular NFT. Marketplaces and dashboards rely on this to surface redeemable rights without maintaining their own off-chain privilege indexers.
Security Considerations
ERC7765 introduces stateful privilege tracking, which means errors in exercise logic can directly affect redeemable rights tied to real-world value. Because privileges may represent legal claims or physical redemptions, maintaining accurate state and clean access controls is essential. The EIP highlights risks around reentrancy, misconfigured operators, and broken privilege state transitions, all of which become more severe in RWA contexts.
Double-Execution and Race Conditions
If multiple calls attempt to exercise the same privilege at once, state tracking can become inconsistent, resulting in multiple redemptions or invalid claims. Mitigation includes performing atomic privilege updates inside exercisePrivilege and following strict checks-effects-interactions ordering. For RWAs, off-chain services should treat events as idempotent, using unique nonces to guard against duplicate fulfillment.
Operator or Approval Abuse
If approvals are too broad, a delegated operator may exercise privileges for unintended recipients or at unintended times. Mitigation includes tying execution strictly to ERC721 ownership and approval flows, or adding role-based layers via AccessControl. In RWA deployments, privileges are often gated through ERC3643-style verification to ensure the beneficiary is legitimately entitled.
Invalid Privilege Identifiers
Calls with invalid privilege IDs can revert and, if mishandled, may cause UI freezes or partial DoS patterns during redemption windows. Mitigation includes pre-validation on the front end using getPrivilegeIds and fuzzing privilege boundaries during audits. View functions should avoid external calls or complex branching to prevent brittle privilege discovery.
Untrusted or Over-Flexible Data Payloads
The _data field can carry proofs, instructions, or metadata, but poorly validated payloads introduce injection risks or unintended execution flows. Mitigation includes rigid parsing rules, never delegating _data directly into calls, and maintaining a strict schema for voucher proofs. In RWAs, _data is typically limited to signature material consumed by oracles, rather than arbitrary commands.
Event Dependence and Fulfillment Guarantees
Off-chain systems rely on PrivilegeExercised as a single source of truth. If events are dropped, reordered, or mishandled, fulfillment processes could break. Mitigation includes redundant indexing (subgraphs, indexers, event mirrors) and well-defined dispute fallbacks. In regulated RWA flows, legal wrappers and custodian policies ensure that missed events do not break entitlement rights.

