Alert Source Discuss
⚠️ Draft Standards Track: ERC

ERC-7085: NFT 关系增强

建立 NFT 之间的关系,并为这些关系设置可量化的属性。

Authors Guang (@xg1990)
Created 2023-05-02
Discussion Link https://ethereum-magicians.org/t/introducing-new-eip-nft-relationship-standard/14468
Requires EIP-721, EIP-1155

摘要

本提案基于 ERC-1155,并为在非隔离的 ERC-721ERC-1155 非同质化代币 (NFT) 之间引用关系和可量化的属性创建了一个标准。它使用户能够构建 NFT 图,并为每个 NFT 设置可量化的属性,从而促进更复杂的 NFT 生态系统。虽然存在一个类似的 ERC-721 代币提案,但它没有提供建立可量化的关系或对象属性的方法。

动机

当前 NFT 的标准缺乏在代币之间建立关系和属性的能力。这种限制使得用户难以构建更复杂的 NFT 生态系统,这些生态系统需要在代币之间引用关系和可量化的属性。例如,用户可以创建一个派生 NFT,该 NFT 引用原始 NFT 并为两个 NFT 之间的关系设置一个可量化的属性,但是如果没有标准化的方法来建立 NFT 之间的关系和属性,那么管理这些生态系统将变得越来越困难和低效。

本提案旨在通过扩展 ERC-721ERC-1155 标准来解决此问题,使其包括建立引用关系和 NFT 之间可量化属性的能力。

通过使用户能够构建更复杂的 NFT 生态系统,本提案将增强 NFT 生态系统,并为 NFT 用例开辟新的可能性。但是,必须考虑潜在的缺点,例如增加的复杂性和 gas 成本,并仔细设计规则以减轻这些问题。

规范

此 EIP 建议向 ERC-721ERC-1155 标准添加五个新函数:setRelationshipsetAttributegetRelationshipgetAttributegetAttributeNames。 这些函数允许用户建立引用关系并在 NFT 之间设置可量化的属性。

setRelationship

setRelationship 函数在两个 NFT 之间建立引用关系。 它采用以下参数:

function setRelationship(uint256 _originalID, uint256 _derivativeID, uint256 _attribute) external;
  • _originalID:原始 NFT 的 ID
  • _derivativeID:引用原始 NFT 的派生 NFT 的 ID
  • _attribute:此关系的可量化属性,如果未指定,则默认为 1

调用时,此函数将在两个 NFT 之间建立引用关系。

setAttribute

setAttribute 函数为 NFT 设置可量化的属性。 它采用以下参数:

function setAttribute(uint256 _id, string calldata _name, uint256 _value) external;
  • _id:NFT 的 ID
  • _name:要设置的属性的名称
  • _value:要设置的属性的值

调用时,此函数将为 NFT 设置可量化的属性。

getAttribute

getAttribute 函数允许任何人检索与 NFT 关联的特定属性的值。它采用以下参数:

function getAttribute(uint256 _id, string calldata _name) external view returns (bytes32);
  • _id: 要检索属性的 NFT 的 ID。
  • _name: 要检索的属性的名称。

此函数以 bytes32 数据类型返回指定属性的值。

getAttributeNames

getAttributeNames 函数允许任何人检索与 NFT 关联的所有属性的名称。它采用以下参数:

function getAttributeNames(uint256 _id) external view returns (bytes32[] memory);
  • _id: 要检索属性名称的 NFT 的 ID。

此函数返回一个 bytes32 值的数组,表示与指定 NFT 关联的所有属性的名称。

getRelationship

getRelationship 函数允许任何人检索两个 NFT 之间的引用关系的值。 它采用以下参数:

function getRelationship(uint256 _originalID, uint256 _derivativeID) external view returns (uint256);
  • _originalID:原始 NFT 的 ID。
  • _derivativeID:引用原始 NFT 的派生 NFT 的 ID。

此函数以 uint256 数据类型返回两个 NFT 之间的引用关系的值。

使用示例

NFTGraph nftContract = NFTGraph(addressOfContract);

// Retrieve the value of an attribute named "Color" for NFT with ID 123
// 检索 ID 为 123 的 NFT 的名为“Color”的属性的值
bytes32 colorValue = nftContract.getAttribute(123, "Color");

// Retrieve the names of all attributes associated with NFT with ID 456
// 检索与 ID 为 456 的 NFT 关联的所有属性的名称
bytes32[] memory attributeNames = nftContract.getAttributeNames(456);

通过在规范中包含这些函数和方法,您可以为用户和开发人员建立一种清晰且标准化的方式来读取与 NFT 关联的属性。

原理

在开发此 EIP 时,做出了一些关键的设计决策。 例如,我们仅允许在两个 NFT 之间建立一个引用关系,从而限制了可以创建的关系图的复杂性。 这有助于确保图保持可管理性,并且不会变得过于复杂而无法使用。 此外,通过仅允许一次设置一个属性,我们将设置属性的 gas 成本降至最低。

尽管目前在其他区块链语言或标准中没有类似的功能,但我们从图论的概念中汲取了灵感,图论是研究对象之间关系的数学分支。 通过添加建立 NFT 之间关系并为这些关系设置可量化属性的功能,我们认为扩展的 NFT 标准对于 NFT 创建者和用户将变得更加有用和通用。

向后兼容性

此 EIP 旨在与现有的 ERC-721ERC-1155 合约和代币完全向后兼容。 现有的 NFT 合约和代币将继续像以前一样运行,并且新的 setRelationshipsetAttribute 函数仅适用于显式实现此 EIP 的合约。

参考实现

为了帮助理解和实施本提案,我们提供了一个参考 Solidity 接口和合约,它们定义了用于建立关系和读取属性的函数。开发人员可以使用此接口作为将 NFT 关系增强集成到他们自己的合约中的基础。

ERC-165 接口支持

NFT 关系增强合约实现了 ERC-165 标准接口,以实现接口检测。 这使智能合约和应用程序可以在与给定合约交互之前,检查该合约是否支持本提案中定义的函数。

INFTGraph 接口

// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;

import "@openzeppelin/contracts/token/ERC165/IERC165.sol";  // Import IERC165 for interface detection
// 导入 IERC165 以进行接口检测

interface INFTGraph is IERC165 {
    // setRelationship: Establishes relationships between NFTs.
    // setRelationship:建立 NFT 之间的关系。
    function setRelationship(uint256 _originalID, uint256 _derivativeID, uint256 _attribute) external;
    // setAttribute: Sets quantifiable attributes for NFTs.
    // setAttribute:为 NFT 设置可量化的属性。
    function setAttribute(uint256 _id, string calldata _name, uint256 _value) external;
    // getRelationship: Retrieves relationship values between NFTs.
    // getRelationship:检索 NFT 之间的关系值。
    function getRelationship(uint256 _originalID, uint256 _derivativeID) external view returns (uint256);
    // getAttribute: Retrieves the value of specific attributes associated with NFTs.
    // getAttribute:检索与 NFT 关联的特定属性的值。
    function getAttribute(uint256 _id, string calldata _name) external view returns (bytes32);
    // getAttributeNames: Retrieves all attribute names associated with an NFT.
    // getAttributeNames:检索与 NFT 关联的所有属性名称。
    function getAttributeNames(uint256 _id) external view returns (bytes32[] memory);
}

INFTGraph 接口指定了用于设置关系和属性的函数,以及检索属性信息和关系值。

NFTGraph 合约

// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;

import "@openzeppelin/contracts/introspection/ERC165.sol";  // Import ERC165 for interface detection
// 导入 ERC165 以进行接口检测

import "./INFTGraph.sol";  // Import INFTGraph interface
// 导入 INFTGraph 接口

contract NFTGraph is INFTGraph{
    mapping(uint256 => mapping(uint256 => uint256)) public relationship;
    mapping(uint256 => mapping(bytes32 => bytes32)) public attributes;

    // Implement the setRelationship and setAttribute functions as described in the EIP specification.
    // 按照 EIP 规范中所述实现 setRelationship 和 setAttribute 函数。


    // Implement the supportsInterface function for ERC-165.
    // 实现 ERC-165 的 supportsInterface 函数。
    function supportsInterface(bytes4 interfaceID) public view override returns (bool) {
        return interfaceID == type(INFTGraph).interfaceId || super.supportsInterface(interfaceID);
    }

    // Additional implementation details...
    // 附加实现细节...
    function getRelationship(uint256 _originalID, uint256 _derivativeID) external view returns (uint256) {
        return relationship[_originalID][_derivativeID];
    }

    function getAttribute(uint256 _id, string calldata _name) external view returns (bytes32) {
        return bytes32(attributes[_id][_name]);
    }

    function getAttributeNames(uint256 _id) external view returns (bytes32[] memory) {
        bytes32[] memory names = new bytes32[](attributes[_id].length);
        for (uint256 i = 0; i < attributes[_id].length; i++) {
            names[i] = bytes32(attributes[_id][i]);
        }
        return names;
    }

    function setRelationship(uint256 originalNFT, uint256 derivativeNFT, uint256 relationshipValue) public {
        require(originalNFT != derivativeNFT, "Original and derivative NFTs must be different");
        // 需要原始 NFT和派生 NFT 不同
        relationship[originalNFT][derivativeNFT] = relationshipValue;
    }
    
    function setAttribute(uint256 nft, bytes32 attributeName, bytes32 attributeValue) public {
        attributes[nft][attributeName] = attributeValue;
    }

}

NFTGraph 合约实现了 INFTGraph 接口中指定的函数,并为关系和属性提供了存储。

开发人员可以使用此参考接口和合约作为将 NFT 关系增强功能集成到他们自己的项目中的起点。 该接口提供了一种清晰且标准化的方式来与合约进行交互,从而提高了集成的一致性和简易性。

安全注意事项

在实施本提案时,合约开发人员应考虑以下安全方面:

  1. 关系验证:利用 setRelationship 函数的合约必须确保所建立的关系是有效的,并且已获得相关方的授权。未经授权或恶意的关系可能会导致意想不到的后果。
  2. 属性验证:实施 setAttribute 函数的合约应仔细验证属性,以防止恶意或有害的值。无效或未经验证的属性可能会破坏 NFT 生态系统的功能。
  3. 访问控制:合约应实施适当的访问控制机制,以限制谁可以调用关键函数,尤其是那些修改关系或属性的函数。未经授权的访问可能导致滥用或利用。
  4. 重入保护:考虑向修改关系或属性的函数添加重入保护机制。否则,可以利用重入攻击来操纵合约行为。

通过解决这些注意事项,开发人员可以增强其合约的安全性,并保护 NFT 生态系统的完整性。

版权

版权及相关权利通过 CC0 放弃。

Citation

Please cite this document as:

Guang (@xg1990), "ERC-7085: NFT 关系增强 [DRAFT]," Ethereum Improvement Proposals, no. 7085, May 2023. [Online serial]. Available: https://eips.ethereum.org/EIPS/eip-7085.