EIP-5521: ERC-721 Referable NFT

Thanks for your positive feedback and question. Let me try:

We are both trying to address NFT dependence problems, but our approaches and focuses are different. While ERC-6551 uses an NFT as a broker/delegator to own the other NFTs on behalf of one or a set of accounts, we try to build the dependency/relationship between NFTs directly using our EIP-5521. We believe our approach is simple/elegant and thus can be used for more application scenarios.

1 Like

From OO Programming viewpoint, ERC-6551 more likes class composition, i.e. a class/NFT can has 1 or more classes; and EIP-5521 more likes class inheritance, i.e. a class/NFT can be generated from/based on another 1 or more classes/NFTs. This is just an analogy, instead of one-2-one mapping.

Thanks for the proposal though, I went through this https://eips.ethereum.org/EIPS/eip-6150 that looks having similar concepts as this one? Would like to know any difference between them?

Thanks for your attention!

ERC-5521 and ERC-6150 differ significantly in their approach to structuring relationships among NFTs. ERC-6150 focuses on creating a hierarchical, filesystem-like structure for NFTs, where each NFT forms part of a tree, acting as either a parent or a child node. This structure typically involves one-to-one relationships, resembling a traditional directory or organizational structure. The standard provides functions to manage these hierarchical relationships, such as determining parent and child nodes, and is fully backward compatible with ERC-721​​​​​​​​.

In contrast, ERC-5521 establishes a more complex network of relationships forming a DAG. This standard allows for multi-NFT compositions, reflecting a wider range of applications than the one-to-one inheritance model of ERC-6150. It introduces referring and referred indicators, along with a createdTimestamp, to track and analyze the lineage and connections of NFTs. Unlike ERC-6150, ERC-5521’s design allows for multiple incoming and outgoing references for each NFT, accommodating a broader spectrum of relationships and interactions​​​​​​.

Furthermore, ERC-5521’s createdTimestamp provides a time-based element to these relationships, which is not explicitly designed or noted in ERC-6150. This feature adds an additional layer of complexity and utility, enabling users to track the temporal aspect of NFT relationships, a consideration not present in the hierarchical model of ERC-6150​​.

Does this answer your question?

Hi, I have two questions for this standard!

  1. Given the open nature of the minting process, what safeguards or best practices are recommended to mitigate the risks of unauthorized references and manipulation? While flexibility is a key advantage, ensuring data integrity and trustworthiness in the referencing system is crucial​​.

  2. How does ERC-5521 interact with other ERC standards, especially in complex scenarios involving multiple types of tokens and contracts? Insights into these interactions and potential challenges would be valuable.

The inherent nature of the ERC-5521 standard does not natively address the risk of off-chain discrepancies (see the note), as it primarily ensures the integrity of data recorded on the blockchain. This limitation is crucial for stakeholders to understand.

Potential solutions to mitigate this risk include: off-chain data verification, reputation mechanisms, cross-verification with external dbs, etc.

In the latest version, ERC-5521 has enabled cross-contract references as long as ERC-20/721 is supported. As you might see this interface:

interface TargetContract {
    /// @notice set the referred list of an rNFT associated with external contract addresses. 
    /// @param `_tokenIds` of rNFTs associated with the contract address `_address` being referred by the rNFT with `tokenId`.
    /// @requirement
    /// - `_address` **MUST NOT** be the same as `address(this)` where `this` is executed by an external contract where `TargetContract` interface is implemented.
    function setNodeReferredExternal(address _address, uint256 tokenId, uint256[] memory _tokenIds) external;

    function referringOf(address _address, uint256 tokenId) external view returns(address[] memory, uint256[][] memory);

    function referredOf(address _address, uint256 tokenId) external view returns(address[] memory, uint256[][] memory);
}

When setNodeReferredExternal is invoked, a cross-contract reference towards TargetContract is leveraged. Also, the basic structure of a rNFT looks like this:

    struct Relationship {
        mapping (address => uint256[]) referring;
        mapping (address => uint256[]) referred;
        uint256 createdTimestamp; // unix timestamp when the rNFT is being created
        // Other labels...
    }

where the address of the TargetContract is the key with an array of the token IDs being the value, given that any type of NFT will have an identical type of identification which would normally be uint256.

So far, this is the level we have developed for compatibility. Does it answer your question? As for further finer-grained compatibility, we need extra standards or functions which are not the current focus.

yeah that is clear to me now

Just one more question. This could be a bit out of scope though, want to know your opinion because of curiosity.

How does the eip-5521 handle changes in ownership of the NFTs, especially in relation to the profit-sharing or rights transfer? While the document mentions that ownership change does not affect the reference relationship, any clarity on the legal and financial implications?

Regarding the legal implications, ERC-5521 barely treats the change of ownership of NFTs in a manner akin to asset trading in the real world. The distribution of profits and the rights associated with an NFT are governed by the agreement terms set when the NFT was initially created. This agreement remains in force regardless of any subsequent changes in ownership. Essentially, the protocol maintains the reference relationship between the tokenIDs, not between the owners. Therefore, if A and C both refer to B, the owner of A is obliged to interact with the current owner of B, irrespective of any changes in the ownership of B, unless otherwise specified in the agreement. The protocol is designed to record only the reference relationships, thereby not mandating any specific legal obligations towards the owners themselves.

As for the financial implications, especially in terms of profit sharing after trading, ERC-5521 does not inherently include a mechanism for profit distribution post-trading. However, we find it useful to refer to another standard, ERC-5173: NFT Future Rewards (nFR) (although it is still a draft the idea is inspired), which introduces a multigenerational reward mechanism for NFT owners. ERC-5173 proposes a Participatory Value Amplification framework where all parties involved - creators, buyers, and sellers - can benefit from future price increases of NFTs. This framework ensures that all sellers, including the original minter, receive equitable Future Rewards (FRs) distributions, reflecting the profits across historical ownership. The innovative approach of ERC-5173 can effectively complement ERC-5521 by providing a structured system for the fair sharing of profits, thus aligning the interests of various stakeholders in the NFT marketplace.

Hi @OniReimu,

Nice work to putting everything up. Love the discussion and reply on comparing 5521 to 6150 which I do see the differences and here’s my comments:

1.l suggest moving referringKeys and referredKeys inside Relationship as it’s the lookup key that should be part relationship

2.l suggest renaming referring to hasMany, referred to belongsTo in order to match existing ORM naming convention and easier for understanding.

3.l suggest remove createdTimestamp and the require check as it’s not necessary. When minting NFT or ERC20 you would just emit the timestamp rather than create a timeStamp storage. Moreover, referred is not necessary to be predecessors as relationship can be create asynchronous.

4.l suggest remove getter function referringOf and referredOf instead just make relationship to be public which would brings in the getter function as a clean up

  1. Following previously can also remove convertMap getter function

  2. l suggest the relationship diagram to show the relationship clearly with actual examples

Overall l think ElP-5521 is not backward compatible as when setting the referred relationship, it requires the existing contract to have setNodeReferredExternal function, which is not part of the ERC-721. In order for backward compatible. Relationship needs to be a separate contract to store all the relationships. That way it can referred to any existing NFT. Just like a mapping table in traditional ORM.

  1. I suggest moving referringKeys and referredKeys inside Relationship as it’s lookup key is the same as _relationship and should be part of relationship

Good point, updated. Thanks.

  1. I suggest renaming referring to hasMany, referred to belongsTo in order to match existing ORM naming convention and easier for understanding.

After a thorough discussion, we humbly propose that referring and referred are the most apt choices to highlight the reference relationship delineated in this standard. These terms not only perfectly align with the standard’s caption but also effectively convey the active and passive aspects of the relationship. The referring conveys the proactive action, while referred denotes the passive reception. We concur with the interpretations of hasMany and belongsTo and are eager to incorporate your insights into our understanding.

  1. I suggest remove createdTimestamp as it and the require check are not necessary. When minting NFT you would emit rather than create a timeStamp storage. Moreover, referred is not necessary to be predecessor as relationship can be create asynchronous.

A key principle of our standard is that an NFT should reference content already accepted by the community (a time-based sequence known by participants). Global timestamps for NFTs are therefore essential, serving to prevent conflicting states (akin to concurrency issues in transaction processing and block organization). This necessitates the verification of NFT timestamps at the time of their creation.

Also, to optimize timestamp synchronization, we define ‘createdTimestamp = block.timestamp.’ This approach is fundamental in our standard, reinforcing the need for NFTs to reference pre-approved content.

Given that the granularity of references is tied to the block timestamp, discerning the order of two NFTs in the same block becomes impractical. This standard is crucial in ensuring clarity and integrity in references, effectively avoiding ambiguities and potential conflicts from ‘in-block references’.

  1. I suggest remove getter function referringOf and referredOf instead just make _relationship to be public which would brings in the getter function.

First, the current referringOf and referredOf allow cross-contract looking up, while this cannot be done by directly accessing _relationship.
Secondly, only if privacy isn’t a concern, making _relationship public simplifies the contract by relying on Solidity’s automatically generated getters. However, if you need to control the visibility of the data, keeping the state variable private and providing specific getter functions would be the best approach. Making _relationship public could inadvertently expose sensitive relationship data between tokens. For example, if _relationship includes details about specific users’ interactions or transactions or some private extensible parameters (in the updated version, we specifically highlight the Relationship can be extended to meet different requirements), always making this data public could reveal users’ behavior patterns or preferences, leading to potential privacy breaches. Keeping such details private and using controlled getter functions prevents unintended data exposure.

  1. Following previously can also remove convertMap

convertMap needs to be used to return the entire mapping. Even if we set the _relationship to public, Solidity can only generate getter functions for public state variables for a given key and a given address (whereas we actually don’t know how many addresses are stored inside). The getter function will not return the mappings contained within the struct, it will only allow you to retrieve individual values from those mappings by specifying their keys, which does not satisfy our definition of the emitted event. Therefore a separate function convertMap needs used to retrieve the entire contents of a mapping within a struct.

  1. I suggest the relationship diagram to show the relationship clearly with example.

We would like to refer you to this link http://arxiv.org/abs/2402.06459 (Fig. 2) where a use case is presented.

  1. Overall I think EIP-5521 is not backward compatible as when setting the referred relationship, it requires the existing contract to have setNodeReferredExternal function. In order for backward compatible, the relationship should be a separate contract to store all the relationships. That way it can referred to any existing NFT.

In the updated version, the setNodeReferredExternal function is conditionally executed based on a successful interface verification. This selective invocation ensures compatibility with existing contracts. For functions like referringOf and referredOf, where cross-contract interactions are crucial, interface verification is essential and must return true. This design ensures that EIP-5521 can integrate with contracts that conform to the specified interfaces, thus maintaining backward compatibility while enabling new features.