mirror of
https://github.com/status-im/EIPs.git
synced 2025-02-24 04:38:29 +00:00
Hi, I'm a bot! This change was automatically merged because: - It only modifies existing Draft, Review, or Last Call EIP(s) - The PR was approved or written by at least one author of each modified EIP - The build is passing
175 lines
9.3 KiB
Markdown
175 lines
9.3 KiB
Markdown
---
|
|
eip: 2981
|
|
title: ERC-721 Royalty Standard
|
|
author: Zach Burks (@vexycats), James Morgan (@jamesmorgan), Blaine Malone (@blmalone), James Seibel (@seibelj)
|
|
discussions-to: https://github.com/ethereum/EIPs/issues/2907
|
|
status: Draft
|
|
type: Standards Track
|
|
category: ERC
|
|
created: 2020-09-15
|
|
requires: 165
|
|
---
|
|
|
|
## Simple Summary
|
|
|
|
A standardized way to handle royalty payments for ERC-721 tokens, including publicly viewable information and notification of payment event.
|
|
|
|
## Abstract
|
|
|
|
This extension provides even more flexibility to the [ERC-721 specification](./eip-721.md). It is possible to set a royalty amount that can be paid to the creator on any marketplace that implements this ERC.
|
|
|
|
|
|
## Motivation
|
|
There are many marketplaces for NFTs and the ones that support royalties are using their own standard version of royalties that are not easily compatible or usable by other marketplaces. Just as in the early days of Ethereum, smart contracts are varied by ecosystem and not compatible. This would solve that issue such that an NFT created, purchased, or sold on one marketplace, provides the royalties that the creator is entitled too, regardless of the next marketplace/ecosystem it is sold at.
|
|
|
|
Many of the largest ERC-721 marketplaces have implemented a form of royalties that is incompatible with other platforms and therefore makes it much harder to enforce when the NFT is sold on another marketplace, not fulfulling the potential of any implemented royalty system. This standard is a way to implement royalties that can be accepted across any type of NFT marketplace smart contracts. This minimalist proposal allows for standardized royalties to be accepted on all marketplaces - leaving the actual funds transfer up to the marketplace itself, and only providing a means to fetch the royalty amounts and an event to be emitted when the transfer has happened.
|
|
|
|
This extension provides even more flexibility to the [ERC-721 specification](./eip-721.md). It is possible to set a royalty amount that can be paid to the creator on any marketplace that implements this ERC. If a marketplace chooses not to implement this ERC, then of course no funds are paid for secondary sales. But as most NFT marketplaces have developed some sort of royalty system themselves - and all of them are singular and only work within their own contracts - there should be an accepted standard way of providing royalties, if the creator chooses to set royalties on their NFTs.
|
|
|
|
Without an agreed standard for implementing royalties, the NFT ecosystem will lack an effective means to collect royalties across all marketplaces. This will hamper the growth and adoption of NFTs and demotivate artists and other NFT creators from minting new and innovative tokens.
|
|
|
|
*"Yes we have royalties, but if your NFT is sold on another marketplace, we cannot provide royalties" .... "But can't I sell my NFT anywhere with a click of my wallet?" .... "Yes... but we don't have a standard for royalties so you'll lose out"*
|
|
|
|
This is the current user experience, which is easily fixed with an accepted standard.
|
|
|
|
## 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.
|
|
|
|
**ERC-721 compliant contracts MAY implement this ERC for royalties to provide a standard method of accepting royalty payments and receiving royalty information**
|
|
|
|
The `_RoyaltyAmount` **MUST** be calculated as a percentage fixed point with a scaling factor of 100000 `(X/100000)` - such as "500000" - for 5%. This is **REQUIRED** to maintain uniformity across the standard. The max and min values would be - 100% (10,000,000) and 0.00001% (1).
|
|
|
|
Marketplaces that support this standard **MAY** implement any method of calculating or transferring royalties to the royalty recipient.
|
|
|
|
Marketplaces that support this standard **MUST** emit the event, `ReceivedRoyalties` by calling the receivedRoyalties() function on the NFT contract after sending a payment.
|
|
|
|
```solidity
|
|
pragma solidity ^0.6.0;
|
|
import "./ERC165.sol";
|
|
|
|
/**
|
|
* @dev Implementation of royalties for 721s
|
|
*
|
|
*/
|
|
interface IERC2981 is ERC165 {
|
|
/*
|
|
* ERC165 bytes to add to interface array - set in parent contract implementing this standard
|
|
*
|
|
* bytes4(keccak256('royaltyInfo(uint256)')) == 0xcef6d368
|
|
* bytes4(keccak256('receivedRoyalties(address,address,uint256,address,uint256)')) == 0x8589ff45
|
|
* bytes4(0xcef6d368) ^ bytes4(0x8589ff45) == 0x4b7f2c2d
|
|
* bytes4 private constant _INTERFACE_ID_ERC721ROYALTIES = 0x4b7f2c2d;
|
|
* _registerInterface(_INTERFACE_ID_ERC721ROYALTIES);
|
|
*/
|
|
/**
|
|
|
|
/**
|
|
* @notice Called to return both the creator's address and the royalty percentage -
|
|
* this would be the main function called by marketplaces unless they specifically
|
|
* need to adjust the royaltyAmount
|
|
* @notice Percentage is calculated as a fixed point with a scaling factor of 100000,
|
|
* such that 100% would be the value 10000000, as 10000000/100000 = 100.
|
|
* 1% would be the value 100000, as 100000/100000 = 1
|
|
*/
|
|
function royaltyInfo(uint256 _tokenId) external returns (address receiver, uint256 amount);
|
|
|
|
/**
|
|
* @notice Called when royalty is transferred to the receiver. We wrap emitting
|
|
* the event as we want the NFT contract itself to contain the event.
|
|
*/
|
|
function receivedRoyalties(address _royaltyRecipient, address _buyer, uint256 _tokenId, address _tokenPaid, uint256 _amount) external;
|
|
}
|
|
|
|
```
|
|
|
|
### Event `ReceivedRoyalties` to be used by marketplaces when transferring royalty payments
|
|
```solidity
|
|
/**
|
|
@notice This event is emitted when royalties are transferred.
|
|
@dev The marketplace would emit this event from their contracts.
|
|
@param royaltyRecipient - The address of who is entitled to the royalties
|
|
@param buyer - The address buying the NFT on a secondary sale
|
|
@param tokenId - the token buying purchased/traded
|
|
@param tokenPaid - The address of the token (ERC20) used to pay the fee. Set to 0x0 if native asset (ETH).
|
|
@param amount - The amount being paid to the creator using the correct decimals from tokenPaid (i.e. if 6 decimals, 1000000 for 1 token paid)
|
|
*/
|
|
event ReceivedRoyalties(
|
|
address indexed _royaltyRecipient,
|
|
address indexed _buyer,
|
|
uint256 indexed _tokenId,
|
|
address _tokenPaid,
|
|
uint256 _amount
|
|
);
|
|
```
|
|
|
|
### Examples
|
|
|
|
The `Royalty` ERC being used on a ERC-721 during deployment:
|
|
|
|
**Deploying an ERC-721 and setting the royalty amount and creator**
|
|
|
|
```solidity
|
|
constructor (string memory name, string memory symbol, string memory baseURI) public Royalties(royalty_amount, msg.sender) {
|
|
_name = name;
|
|
_symbol = symbol;
|
|
_setBaseURI(baseURI);
|
|
// register the supported interfaces to conform to ERC721 via ERC165
|
|
_registerInterface(_INTERFACE_ID_ERC721);
|
|
_registerInterface(_INTERFACE_ID_ERC721_METADATA);
|
|
_registerInterface(_INTERFACE_ID_ERC721_ENUMERABLE);
|
|
// Royalties interface
|
|
_registerInterface(_INTERFACE_ID_ERC721ROYALTIES);
|
|
}
|
|
```
|
|
|
|
**Checking if the NFT being purchased/sold on your marketplace implemented royalties (note using address.call() is completely **OPTIONAL** and is just one method)**
|
|
|
|
```solidity
|
|
function checkRoyalties(address _token) internal returns (bool) {
|
|
(bool success) = address(_token).call(abi.encodeWithSignature("royaltyInfo(uint256)"));
|
|
return success;
|
|
}
|
|
```
|
|
|
|
**Transferring funds (ETH) and calling function to emit the ReceivedRoyalties event inside the NFT contract**
|
|
|
|
```solidity
|
|
_recipient.transfer(amount);
|
|
IERC2981(_tokenAddress).receivedRoyalties(_recipient, _buyer, _tokenId, address(0), amount);
|
|
```
|
|
|
|
**Transferring funds (USDC) and calling function to emit the ReceivedRoyalties event inside the NFT contract**
|
|
|
|
```solidity
|
|
IERC20(0xa0b86991c6218b36c1d19d4a2e9eb0ce3606eb48).transfer(_recipient, amount);
|
|
_recipient.transfer(amount);
|
|
IERC2981(_tokenAddress).receivedRoyalties(_recipient, _buyer, _tokenId, address(0xa0b86991c6218b36c1d19d4a2e9eb0ce3606eb48), amount);
|
|
```
|
|
|
|
## Rationale
|
|
|
|
### Fixed percentage to 10^5 (100000)
|
|
|
|
Having the flexibility to set any percentage a creator likes is important - although the reality of having users want a 0.00000000001% fee is not very likely. Instead the value can be limited to 5 decimal places with the lowest percentage being 0.00001% and the cap at 100%.
|
|
|
|
### Emitting event for payment
|
|
|
|
Choosing to emit an event for payment is important as each NFT contract is standalone, and while a marketplace contract can emit events that an item is sold, the royalty recipient might not be aware/watching the marketplace for a secondary sale of their NFT and therefore would never know they got a payment except for having an increased amount of ETH in their wallet randomly. So calling a function on the parent contract of the NFT being sold is an easy way for the recipient to check on the payments received by their secondary sales.
|
|
|
|
|
|
## Backwards Compatibility
|
|
|
|
Completely compatible with current ERC-721 standards - in fact it requires it.
|
|
|
|
## Security Considerations
|
|
|
|
There are no security considerations related directly to the implementation of this standard.
|
|
|
|
## Copyright
|
|
|
|
Copyright and related rights waived via [CC0](https://creativecommons.org/publicdomain/zero/1.0/).
|