5

How do you include royalties in a normal ERC1155 contract?

Something like this:


// Import 1155 token contract from Openzeppelin

import "https://github.com/OpenZeppelin/openzeppelin-contracts/blob/master/contracts/token/ERC1155/ERC1155.sol";
import "https://github.com/OpenZeppelin/openzeppelin-contracts/blob/master/contracts/access/Ownable.sol";

contract NFTContract is ERC1155, Ownable {
    
    uint256 public constant ARTWORK = 0;
    uint256 public constant PHOTO = 1;
    
    constructor() ERC1155("https://wzh58eid3jnd.usemoralis.com/{id}.json") {
        _mint(msg.sender, ARTWORK, 1, "");
        _mint(msg.sender, PHOTO, 2, "");
    }
    function mint( address to, uint256 id, uint256 amount) public onlyOwner {
        _mint(to, id, amount, "");
    }
    function burn( address from, uint256 id, uint256 amount) public {
        require(msg.sender == from);
        _burn(from, id, amount);
    }
}``` 
1
  • Overriding the mint function to keep the original creator, and always transfer royalties where you use the transfer function
    – Julissa DC
    Nov 17, 2021 at 19:59

2 Answers 2

8

Short Answer:

  • There is currently no single way to achieve this that has been widely adopted.
  • Add the royalty functionality of the platforms you think you will need (like OpenSea). Example provided below.

Long Answer

The NFT World is divided when it comes to Royalties.

As you can see here, OpenSea seems to do this off-chain by allowing you to include the royalty information in your metadata.

Rarible has a seperate smart contract called the Royalties Registry that is used to track the royalties of each NFT.

Various internet sources suggest to add custom code into your transferFrom() functions. However I would advise against this as mentioned in EIP-2981

It is impossible to know which NFT transfers are the result of sales, and which are merely wallets moving or consolidating their NFTs. Therefore, we cannot force every transfer function, such as transferFrom()

Thankfully, this lack of conformity across the NFT space will hopefully change now that EIP-2981: NFT Royalty Standard has recently been approved. It is still early days but some marketplaces like Mintable have already implemented this and there has been public support for OpenSea to do the same.

Given that EIP-2981 is not yet supported by the bigger marketplaces my advice to you would be to:

  1. Add the royalty functionality of the platforms you think you will need (like OpenSea)
  2. Be future proof by also implementing EIP-2981.

Here is an example of how you can support both EIP-2981 and OpenSea given the information you have provided. I have copied some code from this repo.

pragma solidity ^0.8.0;

import "@openzeppelin/contracts/token/ERC1155/ERC1155.sol";
import "@openzeppelin/contracts/access/Ownable.sol";
import '@openzeppelin/contracts/utils/introspection/ERC165.sol';


interface IERC2981Royalties {
    
    function royaltyInfo(uint256 _tokenId, uint256 _value)
        external
        view
        returns (address _receiver, uint256 _royaltyAmount);
}

/// @dev This is a contract used to add ERC2981 support to ERC721 and 1155
abstract contract ERC2981Base is ERC165, IERC2981Royalties {
    struct RoyaltyInfo {
        address recipient;
        uint24 amount;
    }

    /// @inheritdoc ERC165
    function supportsInterface(bytes4 interfaceId)
        public
        view
        virtual
        override
        returns (bool)
    {
        return
            interfaceId == type(IERC2981Royalties).interfaceId ||
            super.supportsInterface(interfaceId);
    }
}

contract NFTContract is ERC1155, Ownable, ERC2981Base {
    
    uint256 public constant ARTWORK = 0;
    uint256 public constant PHOTO = 1;
    RoyaltyInfo private _royalties;
    
    constructor() ERC1155("https://wzh58eid3jnd.usemoralis.com/{id}.json") {
        _setRoyalties({YOUR ADDRESS HERE} , {ROYALTY PERCENTAGE IN BASIS POINTS});
        _mint(msg.sender, ARTWORK, 1, "");
        _mint(msg.sender, PHOTO, 2, "");
    }
    
    // This is just for OpenSea to find your metadata containing the royalties. 
    // This metadata is about the contract and not the individual NFTs
    function contractURI() public view returns (string memory) {
        return "https://metadata-url.com/my-metadata";
    }
    
    function mint( address to, uint256 id, uint256 amount) public onlyOwner {
        _mint(to, id, amount, "");
    }
    function burn( address from, uint256 id, uint256 amount) public {
        require(msg.sender == from);
        _burn(from, id, amount);
    }
    
    
    // Value is in basis points so 10000 = 100% , 100 = 1% etc
    function _setRoyalties(address recipient, uint256 value) internal {
        require(value <= 10000, 'ERC2981Royalties: Too high');
        _royalties = RoyaltyInfo(recipient, uint24(value));
    }


    function royaltyInfo(uint256, uint256 value)
        external
        view
        override
        returns (address receiver, uint256 royaltyAmount)
    {
        RoyaltyInfo memory royalties = _royalties;
        receiver = royalties.recipient;
        royaltyAmount = (value * royalties.amount) / 10000;
    }
    
    function supportsInterface(bytes4 interfaceId) public view virtual override(ERC1155, ERC2981Base) returns (bool) {
        return super.supportsInterface(interfaceId);
    }
    
}

For the contract metadata for OpenSea it might look something like this:

{
  "name": "NFT Contract",
  "description": "Really cool description about my art",
  "image": "https://openseacreatures.io/image.png", # Link to collection image
  "external_link": "https://openseacreatures.io", # Link to website
  "seller_fee_basis_points": 100, # Indicates a 1% seller fee.
  "fee_recipient": "0xA97F337c39cccE66adfeCB2BF99C1DdC54C2D721" # Where seller fees will be paid to.
}
1
  • The problem is, when I run the supportsInterface with "0x2a55205a" (the id of erc2981 I guess) it returns false...
    – MehmedB
    Mar 15, 2022 at 9:05
0

Totally agree with the first answer here. Best bet is to implement EIP 2981 in your contracts, even if not yet supported, and also provide OpenSea with your royalty information. Modifying the transfer functions might prevent exchanges from be able to properly list your collection.

One note: you can manually update royalty information in OpenSea after importing your collection, rather than including it in the contract-level URI. Relevant if you'd like to maintain some flexibility, rather than permanently setting recipient/levels in a JSON.

Aside from royalties, OpenSea suggests a bunch of small additions to streamline collection listing, like whitelisting, meta-transactions, contract-level URI, token-level URI override, etc.

This repo contains all the smart contracts for an ERC 1155 implementation with EIP 2981 royalties, OpenSea-suggested additions, and a bonus hard cap on token/edition supply (that can be removed).

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.