Alert Source Discuss
Standards Track: ERC

ERC-6672: Multi-redeemable NFTs

An extension of ERC-721 which enables an NFT to be redeemed in multiple scenarios for either a physical or digital object

Authors RE:DREAMER Lab <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 (@Jason0729) <jason@redreamer.io>
Created 2023-02-21
Requires EIP-165, EIP-721

Abstract

This EIP proposes an extension to the ERC-721 standard for Non-Fungible Tokens (NFTs) to enable multi-redeemable NFTs. Redemption provides a means for NFT holders to demonstrate ownership and eligibility of their NFT, which in turn enables them to receive a physical or digital item. This extension would allow an NFT to be redeemed in multiple scenarios and maintain a record of its redemption status on the blockchain.

Motivation

The motivation behind our proposed NFT standard is to provide a more versatile and flexible solution compared to existing standards, allowing for multi-redeemable NFTs. Our proposed NFT standard enables multi-redeemable NFTs, allowing them to be redeemed in multiple scenarios for different campaigns or events, thus unlocking new possibilities for commerce use cases and breaking the limitation of one-time redemption per NFT.

One use case for an NFT that can be redeemed multiple times in various scenarios is a digital concert ticket. The NFT could be redeemed for access to the online concert and then again for exclusive merchandise, a meet and greet with the artist, or any exclusive commerce status that is bound to the NFT. Each redemption could represent a unique experience or benefit for the NFT holder.

Specification

The key words “MUST”, “MUST NOT”, “REQUIRED”, “SHALL”, “SHALL NOT”, “SHOULD”, “SHOULD NOT”, “RECOMMENDED”, “NOT RECOMMENDED”, “MAY”, and “OPTIONAL” in this document are to be interpreted as described in RFC 2119 and RFC 8174.

Redeem and Cancel Functions

An operator SHALL only make an update to the redemption created by itself. Therefore, the redeem() and cancel() functions do not have an _operator parameter, and the msg.sender address MUST be used as the _operator.

Redemption Flag Key-Value Pairs

The combination of _operator, _tokenId, and _redemptionId MUST be used as the key in the redemption flag key-value pairs, whose value can be accessed from the isRedeemed() function.

Every contract compliant with this EIP MUST implement ERC6672 and ERC721 interfaces.

pragma solidity ^0.8.16;

/// @title ERC-6672 Multi-Redeemable NFT Standard
/// @dev See https://eips.ethereum.org/EIPS/eip-6672
/// Note: the ERC-165 identifier for this interface is 0x4dddf83f.
interface IERC6672 /* is IERC721 */ {
    /// @dev This event emits when an NFT is redeemed.
    event Redeem(
        address indexed _operator,
        uint256 indexed _tokenId,
        address redeemer,
        bytes32 _redemptionId,
        string _memo
    );

    /// @dev This event emits when a redemption is canceled.
    event Cancel(
      address indexed _operator,
      uint256 indexed _tokenId,
      bytes32 _redemptionId,
      string _memo
    );

    /// @notice Check whether an NFT is already used for redemption or not.
    /// @dev 
    /// @param _operator The address of the operator of the redemption platform.
    /// @param _redemptionId The identifier for a redemption.
    /// @param _tokenId The identifier for an NFT.
    /// @return Whether an NFT is already redeemed or not.
    function isRedeemed(address _operator, bytes32 _redemptionId, uint256 _tokenId) external view returns (bool);

    /// @notice List the redemptions created by the given operator for the given NFT.
    /// @dev
    /// @param _operator The address of the operator of the redemption platform.
    /// @param _tokenId The identifier for an NFT.
    /// @return List of redemptions of speficic `_operator` and `_tokenId`.
    function getRedemptionIds(address _operator, uint256 _tokenId) external view returns (bytes32[]);
    
    /// @notice Redeem an NFT
    /// @dev
    /// @param _redemptionId The identifier created by the operator for a redemption.
    /// @param _tokenId The NFT to redeem.
    /// @param _memo
    function redeem(bytes32 _redemptionId, uint256 _tokenId, string _memo) external;

    /// @notice Cancel a redemption
    /// @dev
    /// @param _redemptionId The redemption to cancel.
    /// @param _tokenId The NFT to cancel the redemption.
    /// @param _memo
    function cancel(bytes32 _redemptionId, uint256 _tokenId, string _memo) external;
}

Metadata Extension

The key format for the redemptions key-value pairs MUST be standardized as operator-tokenId-redemptionId, where operator is the operator wallet address, tokenId is the identifier of the token that has been redeemed, and redemptionId is the redemption identifier. The value of the key operator-tokenId-redemptionId is an object that contains the status and description of the redemption.

  • Redemption status, i.e. status

    The redemption status can have a more granular level, rather than just being a flag with a true or false value. For instance, in cases of physical goods redemption, we may require the redemption status to be either redeemed, paid, or shipping. It is RECOMMENDED to use a string enum that is comprehensible by both the operator and the marketplace or any other parties that want to exhibit the status of the redemption.

  • Description of the redemption, i.e. description

    The description SHOULD be used to provide more details about the redemption, such as information about the concert ticket, a detailed description of the action figures, and more.

The metadata extension is OPTIONAL for ERC-6672 smart contracts (see “caveats”, below). This allows your smart contract to be interrogated for its name and for details about the assets which your NFTs represent.

/// @title ERC-6672 Multi-Redeemable Token Standard, optional metadata extension
/// @dev See https://eips.ethereum.org/EIPS/eip-6672
interface IERC6672Metadata /* is IERC721Metadata */ {
    /// @notice A distinct Uniform Resource Identifier (URI) for a given asset.
    /// @dev Throws if `_tokenId` is not a valid NFT. URIs are defined in RFC
    ///  3986. The URI may point to a JSON file that conforms to the "ERC-6672
    ///  Metadata JSON Schema".
    function tokenURI(uint256 _tokenId) external view returns (string);
}

This is the “ERC-6672 Metadata JSON Schema” referenced above.

{
    "title": "Asset Metadata",
    "type": "object",
    "properties": {
        "name": {
            "type": "string",
            "description": "Identifies the asset to which this NFT represents"
        },
        "description": {
            "type": "string",
            "description": "Describes the asset to which this NFT represents"
        },
        "image": {
            "type": "string",
            "description": "A URI pointing to a resource with mime type image/* representing the asset to which this NFT represents. Consider making any images at a width between 320 and 1080 pixels and aspect ratio between 1.91:1 and 4:5 inclusive."
        }
    },
    "redemptions": {
        "operator-tokenId-redemptionId": {
            "status": {
                "type": "string",
                "description": "The status of a redemption. Enum type can be used to represent the redemption status, such as redeemed, shipping, paid."
            },
            "description": {
                "type": "string",
                "description": "Describes the object that has been redeemed for an NFT, such as the name of an action figure series name or the color of the product."
            }
        }
    }
}

Rationale

Key Choices for Redemption Flag and Status

The combination of _operator, _tokenId, and _redemptionId is chosen as the key because it provides a clear and unique identifier for each redemption transaction.

  • Operator wallet address, i.e. _operator

    It’s possible that there are more than one party who would like to use the same NFT for redemption. For example, MisterPunks NFTs are eligible to be redeemed for both Event-X and Event-Y tickets, and each event’s ticket redemption is handled by a different operator.

  • Token identifier, i.e. _tokenId

    Each NFT holder will have different redemption records created by the same operator. Therefore, it’s important to use token identifier as one of the keys.

  • Redemption identifier, i.e. _redemptionId

    Using _redemptionId as one of the keys enables NFT holders to redeem the same NFT to the same operator in multiple campaigns. For example, Operator-X has 2 campaigns, i.e. campaign A and campaign B, and both campaigns allow for MisterPunks NFTs to be redeemed for physical action figures. Holder of MisterPunk #7 is eligible for redemption in both campaigns and each redemption is recorded with the same _operator and _tokenId, but with different _redemptionId.

Backwards Compatibility

This standard is compatible with ERC-721.

Reference Implementation

The reference implementation of Multi-Redeemable NFT can be found here.

Security Considerations

An incorrect implementation of ERC-6672 could potentially allow an unauthorized operator to access redemption flags owned by other operators, creating a security risk. As a result, an unauthorized operator could cancel the redemption process managed by other operators. Therefore, it is crucial for ERC-6672 implementations to ensure that only the operator who created the redemption, identified using msg.sender, can update the redemption flag using the redeem() and cancel() functions. It is also recommended to isolate the redeem() and cancel() functions from ERC-721 approval models.

This ERC-6672 token is compatible with ERC-721, so wallets and smart contracts capable of storing and handling standard ERC-721 tokens will not face the risk of asset loss caused by incompatible standard implementations.

Copyright and related rights waived via CC0.

Citation

Please cite this document as:

RE:DREAMER Lab <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 (@Jason0729) <jason@redreamer.io>, "ERC-6672: Multi-redeemable NFTs," Ethereum Improvement Proposals, no. 6672, February 2023. [Online serial]. Available: https://eips.ethereum.org/EIPS/eip-6672.