Custom Royalty Splitter

Introduction

The Royalty Engine is a part of the Mojito smart contract system, designed to handle royalties for NFTs (Non-Fungible Tokens) and provide a consistent way to manage and distribute royalties to creators and other stakeholders in the NFT ecosystem.The royalty engine provides a common interface to unify the lookup for various royalty specifications currently in existence.

The objective was to create a gold standard for royalties on the marketplace and other core contracts that was flexible and broad enough to handle different royalty standards with our own royalty standard.This approach supports on-chain royalties in the following standards.

  1. Manifold
  2. EIP2981
  3. ROYALTY_SPLITTER
  4. SUPERRARE
  5. RARIBLEV2
  6. RARIBLEV1
  7. FOUNDATION
  8. ZORA
  9. ARTBLOCKS
  10. KNOWNORIGINV2.

Deployments

GoerliTestnet

Name of the ContractContract address
RoyaltyEngineVersion20x70ff744b6F7db80DaDC98237a37C54af173C0044

Architecture Overview

This architecture ensures that creators and stakeholders can benefit from their NFTs' value even after they are sold or transferred multiple times. The Royalty Engine Contract acts as a central component responsible for managing and retrieving royalty information, while the Marketplace or other Core Contracts facilitates secure and transparent transactions while handling royalty distributions.

  1. Token Owner:
    • Represents the original creator or owner of the NFT.
  2. Collection Owner or Admin:
    • Represents the owner or administrator of an NFT collection.
    • Configures and sets custom royalty information for their NFT through the Royalty Engine Contract.
  3. Core Contracts:
    • The smart contracts that facilitates the buying and selling of NFTs.
    • Interacts with the Royalty Engine Contract to retrieve royalty information for NFTs being transacted.
    • Calculates and distributes royalties to the relevant recipients upon NFT resale or transfer.
  4. Royalty Engine Contract:
    • Manages and stores royalty information for NFTs.
    • Allows token owners and collection owners to set custom royalty configurations for their NFTs.
    • Integrates with various royalty standards and interfaces to retrieve royalty information for NFTs without custom configurations.
    • Provides functions for querying royalty information for specific NFTs and collections.
  5. Royalty Recipients:
    • Represents creators, stakeholders, or beneficiaries entitled to receive royalties.
    • Receives royalties when their NFTs are resold or transferred on the marketplace.
    • Royalty recipients are determined based on the royalty configurations set by the token owner or collection owner.

How it works?

Exactly, when transferring an NFT from the token owner to the buyer on the marketplace, the sale smart contracts interacts with the royalty smart contract to track and retrieve the royalty information. The process can be summarized as follows:

  1. Check Own Royalty Information:
    • The marketplace smart contract first checks if the royalty information for the specific token and collection is available in royaltyEngineV2. This is the custom royalty information set by the collection owner.
    • If the royalty information is available at this contract level, the sale smart contracts then retrieves the recipient addresses (royalty receivers) and their corresponding royalty basis points (percentage shares).
  2. Check if Royalty Information is Available in an External Contract:
    • If neither token-specific nor collection-specific royalties are defined, check if the collection has a registered royalty lookup address in the RoyaltyRegistry.
    • If yes, retrieve and return the royalty information using IRoyaltyEngineV1 from the external contract (royaltyEngine).
  3. Check any Specific Interfaces for Certain Contracts:
    • If the lookup address is set for a specific contract (using royaltyLookupAddress) in royaltyEngineV2 , check if it is an IArtBlocksOverride contract. If yes, use the getRoyalties function to retrieve and return royalty information.
    • If it is an IEIP2981 or RoyaltySplitter contract, use the royaltyInfo function to retrieve and return royalty information.
  4. Check Royalty Information from Other Standards:
    • If none of the specific interfaces match, attempt to use royaltyEngineV1 to retrieve and return royalty information.
    • If the own royalty information is not available (i.e., no custom royalty is configured for the token and collection), it proceeds to check royalty information from other royalty standards.
    • The royalty smart contract makes use of various interfaces and libraries to query royalty information from popular royalty standards such as EIP2981, SuperRare, Rarible, Zora, ArtBlocks, KnownOrigin, and others.
    • It follows a predefined sequence of checking interfaces or standards to find royalty information until it successfully retrieves the recipient addresses and their royalty basis points.
  5. Return Royalty Information:
    • Once the royalty information is obtained from either the own royalty configurations or other royalty standards, the Core contracts to calculate and distribute the appropriate royalties to the creators and stakeholders when the NFT is resold or transferred.

Smart Contract Interaction

Admin Related Methods

function setRoyalty(
        address collectionAddress,
        address payable[] calldata receivers,
        uint256[] calldata basisPoints
    ) external override

Once the necessary validations are done, the **setRoyalty** function will proceed to update the royalty configurations for the given collectionAddress. It will store the receivers and corresponding basisPoints in the contract's storage mapping, associating them with the specific collection.

function setTokenRoyalty(
        address collectionAddress,
        uint256 tokenId,
        address payable[] calldata receivers,
        uint256[] calldata basisPoints
    ) external override 

Once the necessary validations are done, the function will proceed to update the royalty configurations for the given collectionAddress and tokenId. It will store the receivers and corresponding basisPoints in the contract's storage variables or mapping, associating them with the specific token within the collection.

function setRoyaltyLookupAddress(
        address collectionAddress,
        address _royaltyLookupAddress
    ) external nonReentrant

The function requires the sender to be either a Mojito Admin, a Collection Admin, or a Collection Owner. It checks that both the sender and the collection address are not blacklisted.If the conditions are met, it sets the royalty lookup address for the specified collection.

Getter Methods

function getCollectionRoyalty(address collectionAddress)
    external view override
    returns(address payable[] memory recipients,uint256[] memory basisPoints) 

The function simply returns the royalty information as a tuple, allowing external callers to access and utilize the royalty data for the specified collection.

function getRoyalty(address collectionAddress, uint256 tokenId)
    external view override 
    returns(address payable[] memory recipients,uint256[] memory basisPoints)

The **getRoyalty** first checks if there is royalty information available for a particular token and collection at contract level. (Note: Our own royalty information is configured using the same contract.) It then returns the recipient addresses and their basic points. If there is no royalty configured for the token and collection, it means that no own royalty is set up. After that, the contract checks royalty information from other standards.

function getRoyaltySplitshare(
        address collectionAddress,
        uint256 tokenId,
        uint256 amount
    )
        external
        view
        override
        returns (
            address payable[] memory receivers,
            uint256[] memory basisPoints,
            uint256[] memory feeAmount
        )

The **getRoyaltySplitshare** calculates the fee amount to be distributed to each recipient based on their royalty basis points and the given amount.

 function getRoyaltyLookupAppress(
        address collectionAddress
    ) external view returns(address)

It takes the collectionAddress as a parameter and returns the associated royalty lookup address.