DCIPs/EIPS/eip-5560.md

126 lines
4.3 KiB
Markdown

---
eip: 5560
title: Redeemable NFTs
description: Makes an NFT redeemable for a physical object
author: Olivier Fernandez (@fernandezOli), Frédéric Le Coidic (@FredLC29), Julien Béranger (@julienbrg)
discussions-to: https://ethereum-magicians.org/t/eip-redeemable-nft-extension/10589
status: Stagnant
type: Standards Track
category: ERC
created: 2022-08-30
requires: 165, 721
---
## Abstract
The EIP is a Redeemable NFT extension which adds a `redeem` function to [EIP-721](./eip-721.md). It can be implemented when an NFT issuer wants his/her NFT to be redeemed for a physical object.
## Motivation
An increasing amount of NFT issuers such as artists, fine art galeries, auction houses, brands and others want to offer a physical object to the holder of a given NFT. This standard allows EIP-721 NFTs to signal reedemability.
## Specification
_The key words “MUST”, “MUST NOT”, “REQUIRED”, “SHALL”, “SHALL NOT”, “SHOULD”, “SHOULD NOT”, “RECOMMENDED”, “MAY”, and “OPTIONAL” in this document are to be interpreted as described in RFC 2119._
`EIP-721` compliant contracts MAY implement this EIP to provide a standard method of receiving information on redeemability.
The NFT issuer **MUST** decide who is allowed to redeem the NFT, and restrict access to the `redeem()` function accordingly.
Anyone **MAY** access the `isRedeemable()` function to check the redeemability status: it returns `true` when the NFT redeemable, and `false` when already redeemed.
Third-party services that support this standard **MAY** use the `Redeem` event to listen to changes on the redeemable status of the NFT.
Implementers of this standard **MUST** have all of the following functions:
```solidity
import '@openzeppelin/contracts/utils/introspection/ERC165.sol';
/**
* @dev Implementation of Redeemable for ERC-721s
*
*/
interface IRedeemable is ERC165 {
/*
* ERC165 bytes to add to interface array - set in parent contract implementing this standard
*
* bytes4 private constant _INTERFACE_ID_ERC721REDEEM = 0x2f8ca953;
*/
/// @dev This event emits when a token is redeemed.
event Redeem(address indexed from, uint256 indexed tokenId);
/// @notice Returns the redeem status of a token
/// @param tokenId Identifier of the token.
function isRedeemable(uint256 _tokenId) external view returns (bool);
/// @notice Redeeem a token
/// @param tokenId Identifier of the token to redeeem
function redeem(uint256 _tokenId) external;
}
```
The `Redeem` event is emitted when the `redeem()` function is called.
The `supportsInterface` method **MUST** return `true` when called with `0x2f8ca953`.
## Rationale
When the NFT contract is deployed, the `isRedeemable()` function returns `true` by default.
By default, the `redeem()` function visibility is public, so anyone can trigger it. It is **RECOMMENDED** to add a `require` to restrict the access:
```solidity
require(ownerOf(tokenId) == msg.sender, "ERC721Redeemable: You are not the owner of this token");
```
After the `redeem()` function is triggered, `isRedeemable()` function returns `false`.
### `Redeem` event
When the `redeem()` function is triggered, the following event **MUST** be emitted:
```solidity
event Redeem(address indexed from, uint256 indexed tokenId);
```
## Backwards Compatibility
This standard is compatible with EIP-721.
## Reference Implementation
Here's an example of an EIP-721 that includes the Redeemable extension:
```solidity
contract ERC721Redeemable is ERC721, Redeemable {
constructor(string memory name, string memory symbol) ERC721(name, symbol) {
}
function isRedeemable(uint256 tokenId) public view virtual override returns (bool) {
require(_exists(tokenId), "ERC721Redeemable: Redeem query for nonexistent token");
return super.isRedeemable(tokenId);
}
function redeem(uint256 tokenId) public virtual override {
require(_exists(tokenId), "ERC721Redeemable: Redeem query for nonexistent token");
require(ownerOf(tokenId) == msg.sender, "ERC721Redeemable: You are not the owner of this token");
super.redeem(tokenId);
}
function supportsInterface(bytes4 interfaceId) public view override(ERC721, Redeemable) returns (bool) {
return super.supportsInterface(interfaceId);
}
}
```
## Security Considerations
Needs discussion.
## Copyright
Copyright and related rights waived via [CC0](../LICENSE.md).