OpenZeppelin / openzeppelin-contracts

OpenZeppelin Contracts is a library for secure smart contract development.
https://openzeppelin.com/contracts
MIT License
24.93k stars 11.79k forks source link

Create a new ERC721 extension implementing uses #3618

Closed Niceural closed 2 years ago

Niceural commented 2 years ago

🧐 Motivation

Going through Metaplex' documentation (NFT standard for Solana), their metadata account includes a Uses field designed to restrict the use of an NFT. This feature could be used in gaming, event ticketing, and memberships.

📝 Details

Add a ERC721 extension inheriting the ERC721 base contract. This extension would include:

The UseMethod enum would include three use cases:

In the case of a Multiple UseMethod, the remaining uses mapping would be updated at each operation on the token. The remaining uses could only be reduced by the current owner. Once the remaining uses is null, each operation call will be reverted.

Important: What is meant by using a token would have to be clearly defined. The contract could include a function that decrements the remaining uses of the token. The user would then decide how to use this function (for instance: override the transfer functions to decrement).

Amxx commented 2 years ago

Hello @Niceural and that you for raising the issue.

I'm must say I am not familiar with Solana and its standards. Is there any specification beside the documentation you already linked? Is there a reference implementation somewhere?

Niceural commented 2 years ago

Bonjour :)

I tried looking for more detailed information on use cases of Metaplex Uses. It seems to be a very recent feature. Unfortunately, I could not find any guidance on Discord, Docs, or forums. Solana separates logic from data, logic being called Programs and data being called Accounts. Minting an NFT requires the creation of a Metadata Account storing the metadata of the NFT. This metadata account contains the Uses field. The owner of the NFT can execute two instructions on this field: reduce the number of uses (that is use the NFT) and approve a new use authority. As far as I understand, this functionality could be used to do the following:

  1. an NFT is minted to be used in a video game and a certain amount of Uses is set,
  2. the NFT is sold to a player,
  3. the player adds the video game program as a Use authority and uses the NFT in the video game (i.e. the owner allows a program (instructions, logic) to access the Metadata Account (just an array of bytes)),
  4. once the uses is null, the NFT cannot be used in the game.


In the example above, a video game can sell stuff (skins, weapons, objects, etc) in the form of NFTs. These NFTs can then be used in the game and become unusable once the limit is reached. The player would then have to obtain a new NFT to use in the game. I was thinking of the following implementation (not reviewed and with more vulnerabilities than you can imagine):

  enum UseMethod {
    None,
    Burn,
    Single,
    Multiple,
    Used
  }

  uint8 totalUses;

  // tokenId to UseMethod
  mapping(uint256 => UseMethod) private _useMethods;

  // tokenId to caller address to uses amount
  mapping(uint256 => mapping(address => uint8)) private _uses;

  modifier useModifier(uint256 tokenId, address caller) {
    // get token UseMethod
    UseMethod useMethod = _useMethods[tokenId];

    // check that the token is not fully used
    require(useMethod != UseMethod.Used, "Token fully used sorry :(");

    if (useMethod == UseMethod.Single) {
      // if use method is single, set it to Used
      _useMethods[tokenId] = UseMethod.Used;
    } else if (useMethod == UseMethod.Multiple) {
      // logic to decrement the variables tracking the uses
    }

    _;

    // if use method is burn then burn the token
    if (useMethod == UseMethod.Burn) {
      _burn(tokenId);
    }
  }

  function functionThatUsesUses(uint256 tokenId)
    public
    useModifier(tokenId, _msgSender())
  {
    // do something with the nft
  }

This extension would be similar to the Royalty extension in the sense that it is not mentioned in the ERC721 standard but it's still used in NFT Marketplaces and gives more power to the authority who created the NFT. I hope I haven't been too confusing or incorrect. Let me know what you think @Amxx :)

Amxx commented 2 years ago

Thanks for the additional information.

This looks like a Solana thing. Not saying that is bad, but we would need good evidence of the ethereum community needing this. So far we had no request for anything like this, and I am not aware of any ERC standardizing this.

We are not trying to be trend-setters, proposing innovative approaches before they are standard. Rather we are following the trends, and providing safe implementation of patterns vetted by the community.

Niceural commented 2 years ago

Fair enough, thanks for your feedback on that!