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 |
Table of Contents
摘要
本提案基于 ERC-1155,并为在非隔离的 ERC-721 或 ERC-1155 非同质化代币 (NFT) 之间引用关系和可量化的属性创建了一个标准。它使用户能够构建 NFT 图,并为每个 NFT 设置可量化的属性,从而促进更复杂的 NFT 生态系统。虽然存在一个类似的 ERC-721 代币提案,但它没有提供建立可量化的关系或对象属性的方法。
动机
当前 NFT 的标准缺乏在代币之间建立关系和属性的能力。这种限制使得用户难以构建更复杂的 NFT 生态系统,这些生态系统需要在代币之间引用关系和可量化的属性。例如,用户可以创建一个派生 NFT,该 NFT 引用原始 NFT 并为两个 NFT 之间的关系设置一个可量化的属性,但是如果没有标准化的方法来建立 NFT 之间的关系和属性,那么管理这些生态系统将变得越来越困难和低效。
本提案旨在通过扩展 ERC-721 和 ERC-1155 标准来解决此问题,使其包括建立引用关系和 NFT 之间可量化属性的能力。
通过使用户能够构建更复杂的 NFT 生态系统,本提案将增强 NFT 生态系统,并为 NFT 用例开辟新的可能性。但是,必须考虑潜在的缺点,例如增加的复杂性和 gas 成本,并仔细设计规则以减轻这些问题。
规范
此 EIP 建议向 ERC-721 和 ERC-1155 标准添加五个新函数:setRelationship
,setAttribute
,getRelationship
,getAttribute
和 getAttributeNames
。 这些函数允许用户建立引用关系并在 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-721 和 ERC-1155 合约和代币完全向后兼容。 现有的 NFT 合约和代币将继续像以前一样运行,并且新的 setRelationship
和 setAttribute
函数仅适用于显式实现此 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 关系增强功能集成到他们自己的项目中的起点。 该接口提供了一种清晰且标准化的方式来与合约进行交互,从而提高了集成的一致性和简易性。
安全注意事项
在实施本提案时,合约开发人员应考虑以下安全方面:
- 关系验证:利用 setRelationship 函数的合约必须确保所建立的关系是有效的,并且已获得相关方的授权。未经授权或恶意的关系可能会导致意想不到的后果。
- 属性验证:实施 setAttribute 函数的合约应仔细验证属性,以防止恶意或有害的值。无效或未经验证的属性可能会破坏 NFT 生态系统的功能。
- 访问控制:合约应实施适当的访问控制机制,以限制谁可以调用关键函数,尤其是那些修改关系或属性的函数。未经授权的访问可能导致滥用或利用。
- 重入保护:考虑向修改关系或属性的函数添加重入保护机制。否则,可以利用重入攻击来操纵合约行为。
通过解决这些注意事项,开发人员可以增强其合约的安全性,并保护 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.