Create your own
Lesson illustration

Implementing ERC-2981 Royalties

Hello! Welcome back to your course on Ethereum development.

In our last lesson, we built a gas-efficient allowlist for an NFT mint using Merkle proofs, giving you control over the primary sale. Now, let's turn our attention to the lifecycle of an NFT after it has been minted: the secondary market. A key goal for many creators is to earn a percentage from every future resale of their work.

This lesson focuses on how to programmatically and transparently embed royalty information directly into your NFT smart contract.

Learning Outcome: By the end of this lesson, you will be able to implement on-chain royalty mechanisms using the ERC-2981 standard.

We will explore the ERC-2981 standard, implement it in an NFT contract using OpenZeppelin's battle-tested libraries, and understand how marketplaces interact with this standard to honor royalty payments.

1. The Problem and The Standard: ERC-2981

Before ERC-2981, royalty payments were handled off-chain by individual marketplaces like OpenSea. A creator would configure their royalty percentage on the marketplace's website. This approach had significant drawbacks:

  • Centralized & Platform-Dependent: Royalties were only honored on the specific platform where they were configured. If an NFT was sold on a different marketplace, the creator received nothing.
  • Lack of Transparency: The royalty logic was opaque, controlled by the marketplace's private backend.
  • Fragile: If a marketplace changed its policy or went out of business, the royalty stream could be lost.

ERC-2981 was created to solve this by standardizing a universal, on-chain signal for royalty information.

New Way to create PASSIVE INCOME with NFT Royalties

To start, let's get a high-level overview of the problem ERC-2981 solves and how it works. This video from Dapp University provides a clear introduction.

Watch the introduction from 01:03 to 02:54. Focus on understanding how ERC-2981 enables a creator to get paid a royalty anytime their NFT is sold on a compliant marketplace.

How It Works: A Standard Interface

ERC-2981 is a simple standard. A compliant contract must implement two functions:

  1. royaltyInfo(uint256 tokenId, uint256 salePrice) returns (address receiver, uint256 royaltyAmount): This is the core function. A marketplace calls it during a sale, providing the token ID and sale price. The function returns the address that should receive the royalty and the calculated royalty amount.
  2. supportsInterface(bytes4 interfaceId) returns (bool): This is a standard discovery mechanism from ERC-165. When a marketplace provides the ERC-2981 interface ID (0x2a55205a), the function returns true, signaling that the contract supports on-chain royalties.

Crucially, the NFT contract itself does not handle the payment logic. It only provides the information. The marketplace is responsible for calling royaltyInfo and correctly routing the funds.

2. Implementation with OpenZeppelin

As with many common patterns in Solidity, OpenZeppelin provides a secure and easy-to-use implementation of the ERC-2981 standard. We'll use their ERC721Royalty.sol contract.

The implementation involves three main steps:

  1. Inherit: Your NFT contract inherits from ERC721Royalty.
  2. Set Royalty: You define the royalty receiver and the fee percentage.
  3. Override (if needed): Ensure supportsInterface correctly reports all inherited standards.

Let's examine the code.

EIP-2981: Implementing NFT Royalties On-Chain

This guide from Goldrush provides a concise code example and explanation of implementing ERC-2981 with OpenZeppelin. It demonstrates the simplest and most common approach.

Please read the section 'Implement NFT Royalties (ERC 2981)'. Focus on the Solidity code provided. Notice how the contract inherits from ERC721Royalty and uses a function setDefaultRoyalty to set the royalty information.

Setting the Royalty Information

As you saw in the reading, OpenZeppelin's implementation provides helper functions to set the royalty. There are two primary ways to do this:

  1. _setDefaultRoyalty(address receiver, uint96 feeNumerator): This sets a single, collection-wide royalty for all NFTs in the contract. This is the most common approach. You typically call this once in the constructor.
  2. _setTokenRoyalty(uint256 tokenId, address receiver, uint96 feeNumerator): This sets a specific royalty for an individual tokenId. This offers more flexibility but is less common. You would call this in your mint function.

The feeNumerator is specified in "basis points," where 10,000 basis points = 100%.

  • A 5% royalty would be a feeNumerator of 500.
  • A 2.5% royalty would be a feeNumerator of 250.

This convention is used to avoid floating-point arithmetic, which is not natively supported in Solidity.

3. A Complete Walkthrough: NFT and Marketplace

Now let's see the full picture in action. The following video walks through building an NFT contract with royalties and then a simple marketplace contract to demonstrate how the royalty is paid out during a sale.

This will solidify your understanding of how the two contracts interact and serves as a perfect bridge to our next lesson on building marketplaces.

New Way to create PASSIVE INCOME with NFT Royalties

This Dapp University video provides a complete, step-by-step guide to implementing ERC-2981 and testing it with a basic marketplace.

Please watch the following segments: Implementing the NFT Contract (06:09 - 10:27): Pay close attention to how _setTokenRoyalty is called within the mint function. Function Overrides (10:27 - 12:54): Understand why functions like supportsInterface must be overridden when inheriting from multiple contracts. Building the Marketplace (14:39 - 20:21): This is key. Focus on the buy function and see how it calls royaltyInfo on the NFT contract to get the royalty details and then splits the payment between the seller and the artist.

4. The Marketplace's Responsibility

As we've emphasized, the system relies on the marketplace to honor the on-chain information. Let's look more closely at the logic a robust marketplace should implement.

A marketplace contract, when facilitating a sale, should:

  1. Check for ERC-2981 Support: Use a try/catch block to safely call supportsInterface(0x2a55205a) on the NFT contract. This prevents the transaction from failing if the NFT doesn't support royalties.
  2. Query Royalty Info: If supported, call royaltyInfo(tokenId, price).
  3. Perform Sanity Checks: Verify that the returned royaltyAmount is not greater than the price.
  4. Distribute Funds: Transfer the royaltyAmount to the royaltyReceiver and the remainder (price - royaltyAmount) to the seller.

30 Days of Solidity Day 26: Building a Solidity Smart ...

This article provides an excellent breakdown of the marketplace's side of the interaction, including robust code patterns.

Read the sections 'Royalty Handling' and 'Transfer and Payments'. Focus on the code snippets and explanations. Note the use of try/catch for safe interface checking and the final distribution of funds to both the royalty receiver and the seller.

5. Practical Considerations for Real-World Deployment

While ERC-2981 is the modern standard, not all marketplaces adopted it immediately. For a time, major platforms like OpenSea used a different, off-chain method. They would read a contractURI from your contract, which pointed to a JSON file containing collection-level metadata, including royalty information.

While most modern marketplaces now prioritize ERC-2981, being aware of this alternative mechanism is useful for ensuring maximum compatibility.

Adding Royalty to NFT Smart Contract for Opensea and other marketplaces | ERC 2981 Tutorial

This video from Web3 Club explains the difference and shows how to implement both the modern ERC-2981 standard and the older contractURI method for compatibility with marketplaces like OpenSea.

Watch from 01:02 to 04:51. This will clarify the distinction between on-chain ERC-2981 and the off-chain contractURI approach, which is a valuable practical insight.

Conclusion

You have now learned how to embed perpetual, transparent, and platform-agnostic royalties into your NFT projects using the ERC-2981 standard. This is a fundamental tool for ensuring creators are fairly compensated as their work gains value in the secondary market.

Key Takeaways:

  • Standardized Signaling: ERC-2981 provides a universal on-chain function, royaltyInfo, for marketplaces to query royalty details.
  • OpenZeppelin is the Way: The ERC721Royalty contract from OpenZeppelin is the industry-standard tool for a secure and straightforward implementation.
  • Set and Forget: You can set a collection-wide royalty in the constructor (_setDefaultRoyalty) or a per-token royalty during minting (_setTokenRoyalty).
  • A Two-Way Street: Royalties are a partnership. The NFT contract provides the information, but the marketplace contract must implement the logic to read it and distribute the funds.
  • Basis Points: Royalty fees are specified in basis points (where 100 = 1%) to avoid floating-point math.

Next Steps:

In this lesson, we saw a demonstration of a marketplace contract honoring royalties. In our next lesson, we will dive deep into that topic and build the smart contract logic for a simple NFT marketplace supporting fixed-price listings and purchases, fully integrating the royalty payment flow you've just mastered.

Can't find a good explanation? Sign up and we'll make it for you

Sign up