A Comprehensive Guide to ERC-6672: Multi-Redeemable NFTs

A Comprehensive Guide to ERC-6672: Multi-Redeemable NFTs

·

5 min read

In the realm of digital collectables, Non-Fungible Tokens (NFT) made a remarkable wave. Imagine if your NFT could do more than just resting on your digital wallets.

EIP-6672 introduces an extension to ERC-721 standard, with an added feature of creation of Multi-Redeemable NFTs. Learn how these token enable redemption in multiple scenarios, expanding the utility of NFTs.

What are Multi-Redeemable NFTs?

  • Multi-Redeemable NFTs allows for redemption in multiple scenarios, providing verstality in the benefits or items associated with the token.

  • NFT holders can demonstrate their ownership and redeem their token where the redemption status is recorded and maintained on the blockchain.

  • Redemption functionality of NFTs expand their utility in different industries and use-cases including Digital Event Tickets and Gaming items.

NFTs Vs Multi-Redeemable NFTs

Traditional NFTs are commonly used for representing unique digital assets. Once an NFT is minted, it is owned by a single entity and cannot be redeemed for several times.

Multi-Redeemable NFTs allows to be utilised for multiple times in various scenarios enabling token holder to access different benefits, experience or to receive items associated with the NFT.

For Example, Binding NFTs to ticket redemption can enrich event experience, where it can be redeemed for access to the event, exclusive merchandise or to avail any benefits related to that event.

Multi-Redeemable Event Tickets with ERC-6672

In the digital era of digital experiences, Multi-redeemable tickets brings a new level of versatility. Traditional tickets are transformed into digital asset, where ticket holders can redeem multiple times for availing exclusive benefits.

How Does it Works?

  1. Ticket Purchase : Mint ERC-6672 compliant NFTs as event tickets.

  2. Initial Redemption : Getting access to event and after participation NFTs redemption status is updated by operator.

  3. Claim more exclusive benefits : The same NFT can be used for purchasing related to the event or access exclusive benefits.

Core Functionalities

Redemption Functions: Two functions for managing redemption are ‘redeem() and cancel()’ , allows NFT holders and operator to interact with redemption process. The redemption flag key-value pairs, based on the combination of operator, tokenId, and _redemptionId, play a crucial role in tracking the status of each redemption.

Metadata Extension: Functionality to enhance the information associated with each NFT. It is useful in cases for providing additional details about the redemption.

Backward Compatibility: ERC-6672 is compatible with existing Non-Fungible token standard ensuring smart contracts and wallets that interacts with ERC-721 can also easily integrate multi-redeemable features securely.

Security: Operator who created redemption can only update redemption flags using redeem and cancel functions, this ensures security since operator is identified using the msg.sender.

Here is a sample implementation contract on this use-case:

// SPDX-License-Identifier: MIT
pragma solidity >=0.8.0 <0.9.0;

import "@openzeppelin/contracts/token/ERC721/ERC721.sol";
import "@openzeppelin/contracts/utils/structs/EnumerableSet.sol";
import "@openzeppelin/contracts/token/ERC721/IERC721.sol";

interface IERC6672  is IERC721 {
    event Redeem(
        address indexed _operator,
        uint256 indexed _tokenId,
        address indexed redeemer,
        bytes32 _redemptionId,
        string _memo
    );
    event Cancel(
        address indexed _operator,
        uint256 indexed _tokenId,
        bytes32 _redemptionId,
        string _memo
    );

    function isRedeemed(address _operator, bytes32 _redemptionId, uint256 _tokenId) external view returns (bool);
    function getRedemptionIds(address _operator, uint256 _tokenId) external view returns (bytes32[] memory);
    function redeem(bytes32 _redemptionId, uint256 _tokenId, string memory _memo) external;
    function cancel(bytes32 _redemptionId, uint256 _tokenId, string memory _memo) external;
}

contract EventNFT is ERC721, IERC6672 {
    using EnumerableSet for EnumerableSet.Bytes32Set;

    bytes4 public constant IERC6672_ID = type(IERC6672).interfaceId;

    mapping(address => mapping(uint256 => mapping(bytes32 => bool))) redemptionStatus;
    mapping(address => mapping(uint256 => mapping(bytes32 => string)))
        public memos;
     mapping(address => mapping(uint256 => EnumerableSet.Bytes32Set))redemptions;

    constructor() ERC721("Event Ticket NFT", "ETNFT") {}

    function mint(address to, uint256 tokenId) external {
        _mint(to, tokenId);
    }

    function isRedeemed(
        address _operator,
        bytes32 _redemptionId,
        uint256 _tokenId
    ) external view returns (bool) {
        return _isRedeemed(_operator, _redemptionId, _tokenId);
    }

      function getRedemptionIds(
        address _operator,
        uint256 _tokenId
    ) external view override returns (bytes32[] memory) {
        return redemptions[_operator][_tokenId].values();
    }

    function redeem(bytes32 _redemptionId, uint256 _tokenId, string memory _memo) external override {
        address _operator = msg.sender;
        require(
            !_isRedeemed(_operator, _redemptionId, _tokenId),
            "ERC6672: token already redeemed."
        );
        _update(_operator, _redemptionId, _tokenId, _memo, true);
        redemptions[_operator][_tokenId].add(_redemptionId);
        emit Redeem(
            _operator,
            _tokenId,
            ownerOf(_tokenId),
            _redemptionId,
            _memo
        );
    }

    function cancel(bytes32 _redemptionId, uint256 _tokenId, string memory _memo) external override {
        address _operator = msg.sender;
        require(
            _isRedeemed(_operator, _redemptionId, _tokenId),
            "ERC6672: token not redeemed."
        );
        _update(_operator, _redemptionId, _tokenId, _memo, false);
        _removeRedemption(_operator, _redemptionId, _tokenId);
        emit Cancel(_operator, _tokenId, _redemptionId, _memo);
    }

    function _isRedeemed(address _operator, bytes32 _redemptionId, uint256 _tokenId) internal view returns (bool) {
        return redemptionStatus[_operator][_tokenId][_redemptionId];
    }

    function _update(address _operator, bytes32 _redemptionId, uint256 _tokenId, string memory _memo, bool isRedeemed_) internal {
        redemptionStatus[_operator][_tokenId][_redemptionId] = isRedeemed_;
        memos[_operator][_tokenId][_redemptionId] = _memo;
        if (isRedeemed_) {
            emit Redeem(
                _operator,
                _tokenId,
                ownerOf(_tokenId),
                _redemptionId,
                _memo
            );
        } else {
            emit Cancel(_operator, _tokenId, _redemptionId, _memo);
        }
    }

    function _removeRedemption(address _operator, bytes32 _redemptionId, uint256 _tokenId) internal {
        redemptions[_operator][_tokenId].remove(_redemptionId);
    }

}

Challenges and Risks

  1. Development complexities: Multi-Redeemable NFTs implementation requires additional complexities compared to traditional NFTs. Developers need to test and audit smart contract thoroughly the redemption scenarios.

  2. Vulnerabilities: Unauthorised access to redemption may leads to security concerns. Implement strict access controls, ensuring only authorized operators can update redemption flags.

Conclusion

Multi-Redeemable NFTs aims to revolutionise the NFT landscape, allowing for varied and multiple redemption, expanding the potential use cases and possibilities for commerce and user engagement in the decentralised digital realm. As NFT space continues to evolve, implementation of ERC-6672 enhances the utility of digital assets.

About BuildBear:

BuildBear is a platform for testing dApps at scale, for teams. It provides users with their own private Testnet to test their smart contracts and dApps, which can be forked from any EVM chain. It also provides a Faucet, Explorer, and RPC for testing purposes.

BuidBear aims to build an ecosystem of tools for testing dApps at scale for the teams.

Connect with us on Twitter||LinkedIn||Telegram||GitHub
Author: chandan and Sana