This ERC proposes Royalty Distribution, a standalone royalty distribution for Referable Non-Fungible Tokens (rNFTs). It enables royalty distribution to multiple recipients at the primary level and referenced NFTs in the directed acyclic graph (DAG), with a single depth limit to control propagation. The standard is independent of ERC-2981. and token-standard-agnostic, but expects ERC-5521 rNFTs, which in practice build on ERC-721 ownership semantics. It includes a function to query fixed royalty amounts (in basis points) for transparency. Royalties are voluntary, transparent, and configurable on-chain, supporting collaborative ecosystems and fair compensation.
ERC-5521 introduces Referable NFTs (rNFTs), which form a DAG through "referring" and "referred" relationships. Existing royalty standards like ERC-2981 do not account for this structure or support multiple recipients per level. This EIP addresses the need for a royalty mechanism that:
The key words "MUST", "MUST NOT", "REQUIRED", "SHALL", "SHALL NOT", "SHOULD", "SHOULD NOT", "RECOMMENDED", "MAY", and "OPTIONAL" in this document are to be interpreted as described in RFC 2119.
The IRNFTRoyalty interface defines the royalty distribution for rNFTs and MUST inherit ERC165 so that supporting contracts can advertise compliance via ERC-165:
supportsInterface(type(IRNFTRoyalty).interfaceId).AccessControl) SHOULD be forwarded via super.supportsInterface(interfaceId) when using inheritance.To support gas-efficient and flexible configuration, implementations MUST support the following semantics for the signature overload:
CONFIGURATOR_ROLE, orIERC721(rNFTContract).ownerOf(tokenId) at verification time.block.timestamp; signatures with block.timestamp > deadline MUST be rejected.RECOMMENDED EIP-712 Domain
address(this)RECOMMENDED Typed Struct
RoyaltyInfo:
royaltyAmount: The royalty amount, in wei for getReferenceRoyaltyInfo with salePrice, or basis points (e.g., 100 = 1%) for getReferenceRoyaltyInfo without salePrice.ReferenceRoyalty:
royaltyInfos: An array of RoyaltyInfo for multiple recipients at the primary level and referenced NFTs.referenceDepth: A single value limiting royalty distribution to referenced NFTs in the DAG.getReferenceRoyaltyInfo(address rNFTContract, uint256 tokenId, uint256 salePrice):
ReferenceRoyalty struct with royalty amounts in wei, calculated from the salePrice.referenceDepth.salePrice is zero.getReferenceRoyaltyInfo(address rNFTContract, uint256 tokenId):
ReferenceRoyalty struct with fixed royalty amounts in basis points (e.g., 100 = 1%).referenceDepth.setReferenceRoyalty(address rNFTContract, uint256 tokenId, address[] recipients, uint256[] royaltyFractions, uint256 referenceDepth):
recipients and royaltyFractions (in basis points) define primary-level royalties.referenceDepth limits royalty distribution to referenced NFTs.setReferenceRoyalty(address rNFTContract, uint256 tokenId, address[] recipients, uint256[] royaltyFractions, uint256 referenceDepth, address signer, uint256 deadline, bytes signature):
supportsReferenceRoyalties():
royaltyNonce(address signer, address rNFTContract, uint256 tokenId) external view returns (uint256):
ReferenceRoyaltiesPaid: Emitted when royalties are paid, logging the rNFT contract, token ID, buyer, marketplace, and ReferenceRoyalty details (with royaltyAmount in wei).royaltyInfos array specifies multiple recipients and their fractions (e.g., 5% total, split as 3% and 2%).REFERRED_ROYALTY_FRACTION (e.g., 200 bps / 2%) is carved out and distributed across all referenced NFTs at that depth proportional to their configured weights (fallback: evenly if all weights are zero).royaltyFractions. Propagated/reference-level flows are governed separately by REFERRED_ROYALTY_FRACTION and referenceDepth.referenceDepth; this reference implementation enforces <= 3 (RECOMMENDED).getReferenceRoyaltyInfo function without salePrice returns royalty fractions in basis points, enabling transparent inspection.For an rNFT (contract 0xABC, token ID 1) with referenceDepth = 2:
Configuration:
referenceDepth).getReferenceRoyaltyInfo(0xABC, 1):
Returns:
{ royaltyInfos: [ {recipient: creator, royaltyAmount: 300}, {recipient: collaborator, royaltyAmount: 200}, {recipient: tokenA_owner, royaltyAmount: 100}, {recipient: tokenB_owner, royaltyAmount: 100} ], referenceDepth: 2 }.
Sale for 100 ETH:
getReferenceRoyaltyInfo(0xABC, 1, 100 ether) returns:
{ royaltyInfos: [ {recipient: creator, royaltyAmount: 3 ether}, {recipient: collaborator, royaltyAmount: 2 ether}, {recipient: tokenA_owner, royaltyAmount: 1 ether}, {recipient: tokenB_owner, royaltyAmount: 1 ether} ], referenceDepth: 2 }.
getReferenceRoyaltyInfo function without salePrice allows users to inspect fixed royalty fractions (in basis points), improving transparency.RoyaltyInfo array supports collaborative projects.This standard is independent of ERC-2981 and targets ERC-5521 rNFTs, which in practice build on ERC-721 ownership semantics. Marketplaces can integrate by:
supportsInterface(type(IRNFTRoyalty).interfaceId).getReferenceRoyaltyInfo (with or without sale price).setReferenceRoyalty MUST be restricted to authorized roles (e.g., via AccessControl).royaltyFractions. Propagated/reference-level flows are governed separately by REFERRED_ROYALTY_FRACTION and referenceDepth.referenceDepth MUST be capped (e.g., ≤ 3) to avoid high gas costs.Copyright and related rights waived via CC0.