Alert Source Discuss
Standards Track: ERC

ERC-6672: 多次可兑换的 NFT

ERC-721 的一个扩展,它使 NFT 能够在多种情况下兑换为实物或数字物品

Authors RE:DREAMER 实验室 <dev@redreamer.io>, Archie Chang (@ArchieR7) <archie@redreamer.io>, Kai Yu (@chihkaiyu) <kai@redreamer.io>, Yonathan Randyanto (@Randyanto) <randy@redreamer.io>, Boyu Chu (@chuboyu) <boyu@redreamer.io>, Boxi Li (@boxi79) <boxi@redreamer.io>, Jason Cheng (@JasonCheng0729) <jason@redreamer.io>
Created 2023-02-21
Requires EIP-165, EIP-721

摘要

本 EIP 提出了 ERC-721 标准的扩展,用于不可替代代币 (NFT) 以启用多次可兑换的 NFT。兑换为 NFT 持有者提供了一种证明其 NFT 的所有权和资格的方式,这反过来又使他们能够收到实物或数字商品。此扩展将允许 NFT 在多种情况下被兑换,并在区块链上保持其兑换状态的记录。

动机

我们提出的 NFT 标准背后的动机是提供一种比现有标准更通用和灵活的解决方案,从而允许多次可兑换的 NFT。我们提出的 NFT 标准启用了多次可兑换的 NFT,允许它们在多种情况下兑换为不同的活动或事件,从而为商业用例开启了新的可能性,并打破了每个 NFT 只能兑换一次的限制。

可以在各种场景中多次兑换的 NFT 的一个用例是数字音乐会门票。该 NFT 可以兑换以访问在线音乐会,然后再次兑换以获得独家商品、与艺术家见面和问候,或与该 NFT 绑定的任何独家商业状态。每次兑换都可能代表 NFT 持有者的独特体验或利益。

规范

本文档中的关键词“必须”,“不得”,“必需”,“应”,“不应”,“推荐”,“不推荐”,“可以”和“可选”应按照 RFC 2119 和 RFC 8174 中的描述进行解释。

兑换和取消函数

操作员应仅对其自身创建的兑换进行更新。因此,redeem()cancel() 函数没有 _operator 参数,并且 msg.sender 地址必须用作 _operator

兑换标志键值对

_operator_tokenId_redemptionId 的组合必须用作兑换标志键值对中的键,其值可以从 isRedeemed() 函数访问。

每个符合此 EIP 的合约都必须实现 ERC6672ERC721 接口。

pragma solidity ^0.8.16;

/// @title ERC-6672 多次可兑换 NFT 标准
/// @dev 参见 https://eips.ethereum.org/EIPS/eip-6672
/// 注意:此接口的 ERC-165 标识符为 0x4dddf83f。
interface IERC6672 /* is IERC721 */ {
    /// @dev 当 NFT 被兑换时,会发出此事件。
    event Redeem(
        address indexed _operator,
        uint256 indexed _tokenId,
        address redeemer,
        bytes32 _redemptionId,
        string _memo
    );

    /// @dev 当兑换被取消时,会发出此事件。
    event Cancel(
      address indexed _operator,
      uint256 indexed _tokenId,
      bytes32 _redemptionId,
      string _memo
    );

    /// @notice 检查 NFT 是否已被用于兑换。
    /// @dev 
    /// @param _operator 兑换平台的操作员地址。
    /// @param _redemptionId 兑换的标识符。
    /// @param _tokenId NFT 的标识符。
    /// @return NFT 是否已被兑换。
    function isRedeemed(address _operator, bytes32 _redemptionId, uint256 _tokenId) external view returns (bool);

    /// @notice 列出给定操作员为给定 NFT 创建的兑换。
    /// @dev
    /// @param _operator 兑换平台的操作员地址。
    /// @param _tokenId NFT 的标识符。
    /// @return `_operator` 和 `_tokenId` 的特定兑换列表。
    function getRedemptionIds(address _operator, uint256 _tokenId) external view returns (bytes32[]);
    
    /// @notice 兑换 NFT
    /// @dev
    /// @param _redemptionId 操作员为兑换创建的标识符。
    /// @param _tokenId 要兑换的 NFT。
    /// @param _memo
    function redeem(bytes32 _redemptionId, uint256 _tokenId, string _memo) external;

    /// @notice 取消兑换
    /// @dev
    /// @param _redemptionId 要取消的兑换。
    /// @param _tokenId 要取消兑换的 NFT。
    /// @param _memo
    function cancel(bytes32 _redemptionId, uint256 _tokenId, string _memo) external;
}

元数据扩展

redemptions 键值对的键格式必须被标准化为 operator-tokenId-redemptionId,其中 operator 是操作员钱包地址,tokenId 是已兑换的代币的标识符,redemptionId 是兑换标识符。键 operator-tokenId-redemptionId 的值是一个对象,其中包含兑换的 statusdescription

  • 兑换状态,即 status

    兑换状态可以具有更精细的级别,而不仅仅是具有 truefalse 值的标志。例如,在实物商品兑换的情况下,我们可能要求兑换状态为 redeemedpaidshipping。建议使用操作员、市场或任何其他想要展示兑换状态的各方都可理解的字符串枚举。

  • 兑换的描述,即 description

    description 应该用于提供有关兑换的更多详细信息,例如有关音乐会门票的信息、动作人物的详细描述等等。

对于 ERC-6672 智能合约,元数据扩展是可选的(请参阅下面的“注意事项”)。这允许查询您的智能合约的名称以及有关您的 NFT 所代表的资产的详细信息。

/// @title ERC-6672 多次可兑换代币标准,可选元数据扩展
/// @dev 参见 https://eips.ethereum.org/EIPS/eip-6672
interface IERC6672Metadata /* is IERC721Metadata */ {
    /// @notice 给定资产的不同统一资源标识符 (URI)。
    /// @dev 如果 `_tokenId` 不是有效的 NFT,则抛出。URI 在 RFC 中定义
    ///  3986。URI 可以指向符合 "ERC-6672
    ///  元数据 JSON 模式" 的 JSON 文件。
    function tokenURI(uint256 _tokenId) external view returns (string);
}

这是上面引用的“ERC-6672 元数据 JSON 模式”。

{
    "title": "资产元数据",
    "type": "object",
    "properties": {
        "name": {
            "type": "string",
            "description": "标识此 NFT 所代表的资产"
        },
        "description": {
            "type": "string",
            "description": "描述此 NFT 所代表的资产"
        },
        "image": {
            "type": "string",
            "description": "指向资源(MIME 类型为 image/*)的 URI,表示此 NFT 所代表的资产。考虑使任何图像的宽度在 320 到 1080 像素之间,宽高比在 1.91:1 到 4:5 之间(含)。"
        }
    },
    "redemptions": {
        "operator-tokenId-redemptionId": {
            "status": {
                "type": "string",
                "description": "兑换的状态。枚举类型可用于表示兑换状态,例如已兑换、运输中、已付款。"
            },
            "description": {
                "type": "string",
                "description": "描述已兑换 NFT 的对象,例如动作人物系列名称或产品的颜色。"
            }
        }
    }
}

理由

兑换标志和状态的关键选择

选择 _operator_tokenId_redemptionId 的组合作为键,因为它为每个兑换事务提供了一个清晰且唯一的标识符。

  • 操作员钱包地址,即 _operator

    可能有多方希望使用同一 NFT 进行兑换。例如,MisterPunks NFT 有资格兑换 Event-X 和 Event-Y 门票,并且每个事件的门票兑换都由不同的操作员处理。

  • 代币标识符,即 _tokenId

    每个 NFT 持有者将具有同一操作员创建的不同兑换记录。因此,将代币标识符用作其中一个键非常重要。

  • 兑换标识符,即 _redemptionId

    使用 _redemptionId 作为其中一个键使 NFT 持有者能够将同一 NFT 兑换给同一操作员的多个活动。例如,操作员-X 有 2 个活动,即活动 A 和活动 B,并且这两个活动都允许将 MisterPunks NFT 兑换为实体动作人物。MisterPunk #7 的持有者有资格在两个活动中进行兑换,并且每次兑换都使用相同的 _operator_tokenId 记录,但使用不同的 _redemptionId

向后兼容性

此标准与 ERC-721 兼容。

参考实现

可以在此处找到多次可兑换 NFT 的参考实现。

安全考虑事项

ERC-6672 的不正确实现可能会允许未经授权的操作员访问其他操作员拥有的兑换标志,从而产生安全风险。因此,未经授权的操作员可能会取消由其他操作员管理的兑换过程。因此,对于 ERC-6672 实现来说,至关重要的是确保只有创建兑换的操作员(使用 msg.sender 识别)才能使用 redeem()cancel() 函数更新兑换标志。还建议将 redeem()cancel() 函数与 ERC-721 批准模型隔离。

ERC-6672 代币与 ERC-721 兼容,因此能够存储和处理标准 ERC-721 代币的钱包和智能合约不会面临因不兼容标准实现而导致的资产损失风险。

版权

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

Citation

Please cite this document as:

RE:DREAMER 实验室 <dev@redreamer.io>, Archie Chang (@ArchieR7) <archie@redreamer.io>, Kai Yu (@chihkaiyu) <kai@redreamer.io>, Yonathan Randyanto (@Randyanto) <randy@redreamer.io>, Boyu Chu (@chuboyu) <boyu@redreamer.io>, Boxi Li (@boxi79) <boxi@redreamer.io>, Jason Cheng (@JasonCheng0729) <jason@redreamer.io>, "ERC-6672: 多次可兑换的 NFT," Ethereum Improvement Proposals, no. 6672, February 2023. [Online serial]. Available: https://eips.ethereum.org/EIPS/eip-6672.