Skip to content

Secondary Royalties on Mintable (ERC2981)

Mintable builds upon ERC2981, the NFT Royalties Standard.

Luckily we just have to make minor modifications to support this.

First, it needs to support the interface bytes4 private constant _INTERFACE_ID_ERC2981 = 0x2a55205a;

Secondly, it needs to report back royalties when queried

 function royaltyInfo(
        uint256 _tokenId,
        uint256 _salePrice
    ) external view returns (
        address receiver,
        uint256 royaltyAmount

All we need to do is integrate this function. One option would be to multiply the royalties for the token with the sales price / 100.

Let's integrate it into our Smart Contract:

//SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;

import "@openzeppelin/contracts/token/ERC721/ERC721.sol";
import "@openzeppelin/contracts/access/Ownable.sol";
import "@openzeppelin/contracts/utils/Counters.sol";
import "./@rarible/royalties/contracts/impl/RoyaltiesV2Impl.sol";
import "./@rarible/royalties/contracts/LibPart.sol";
import "./@rarible/royalties/contracts/LibRoyaltiesV2.sol";

contract MinimalERC721 is ERC721, Ownable, RoyaltiesV2Impl {
    using Counters for Counters.Counter;
    Counters.Counter private _tokenIdTracker;

    bytes4 private constant _INTERFACE_ID_ERC2981 = 0x2a55205a;
    constructor() ERC721("Minimal", "MIN") {}

    function mint(address _to) public onlyOwner {
        super._mint(_to, _tokenIdTracker.current());

    function setRoyalties(uint _tokenId, address payable _royaltiesReceipientAddress, uint96 _percentageBasisPoints) public onlyOwner {
        LibPart.Part[] memory _royalties = new LibPart.Part[](1);
        _royalties[0].value = _percentageBasisPoints;
        _royalties[0].account = _royaltiesReceipientAddress;
        _saveRoyalties(_tokenId, _royalties);

    function royaltyInfo(uint256 _tokenId, uint256 _salePrice) external view returns (address receiver, uint256 royaltyAmount) {
        LibPart.Part[] memory _royalties = royalties[_tokenId];
        if(_royalties.length > 0) {
            return (_royalties[0].account, (_salePrice * _royalties[0].value)/10000);
        return (address(0), 0);


    function supportsInterface(bytes4 interfaceId) public view virtual override(ERC721) returns (bool) {
        if(interfaceId == LibRoyaltiesV2._INTERFACE_ID_ROYALTIES) {
            return true;
        if(interfaceId == _INTERFACE_ID_ERC2981) {
            return true;
        return super.supportsInterface(interfaceId);


If you test it again on the truffle developer console, you will get this result:

Unable To Test

Unfortunately there is no test-platform for mintable. So, the implementation is on a "best guess" basis at the moment.

But there is one component still missing - that's the token URI. Let's add that before concluding this tutorial!

Last update: August 19, 2021