# Guide to NFT Royalty Enforcement: Integrating Royalties Into Your Smart Contract

## 1\. Why NFT Royalties Matter

Royalties enable creators to benefit from their work **long after the initial sale**. But enforcement is not just a technical problem; it’s also about incentives, market adoption, and smart contract standards. *the “code is law” idea has limits, and social norms + tooling matter as much as code.*

## 2\. NFT Royalty Enforcement

* **On-chain Royalties**: Encoded into smart contracts (ERC-2981 standard).
    
* **Off-chain Enforcement**: Marketplaces read royalty info, but may or may not pay.
    
* **Direct Transfers**: Peer-to-peer (gift, OTC) usually *don’t* enforce royalties.
    

**Goal:** Maximize royalty receipt **without crippling liquidity or user experience**.

## 3\. Standards, Limits & Marketplace Reality

### ERC-721

* “One NFT, one ID” (unique tokens).
    
* Royalties via ERC-2981, with one global default or token-specific settings.
    

### ERC-1155

* “Semi-fungible”: multiple copies per ID.
    
* Great for games, membership passes, tickets, PFP editions.
    
* Supports batch transfers—royalty logic can be more complex.
    

### ERC-2981 (Royalty Standard)

* **Function:**
    
    ```solidity
    function royaltyInfo(uint256 tokenId, uint256 salePrice) external view returns (address receiver, uint256 royaltyAmount);
    ```
    
* Marketplaces call this to find out who gets paid and how much.
    

## 4\. Royalty Implementation

Let’s build an **ERC-1155 contract** with advanced royalty support (using OpenZeppelin 4.x+).

### **A. Install OpenZeppelin**

```bash
npm install @openzeppelin/contracts
```

### **B. Solidity Contract Example**

```solidity
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.20;

import "@openzeppelin/contracts/token/ERC1155/ERC1155.sol";
import "@openzeppelin/contracts/token/common/ERC2981.sol";
import "@openzeppelin/contracts/access/Ownable.sol";

contract SeasonalsNFT1155 is ERC1155, ERC2981, Ownable {
    constructor(
        string memory uri_,
        address defaultRoyaltyReceiver,
        uint96 defaultRoyaltyFee // e.g., 500 = 5%
    ) ERC1155(uri_) {
        _setDefaultRoyalty(defaultRoyaltyReceiver, defaultRoyaltyFee);
    }

    // Set token-specific royalty (optional, overrides default)
    function setTokenRoyalty(
        uint256 tokenId,
        address receiver,
        uint96 feeNumerator
    ) external onlyOwner {
        _setTokenRoyalty(tokenId, receiver, feeNumerator);
    }

    // Remove royalty for a specific token
    function resetTokenRoyalty(uint256 tokenId) external onlyOwner {
        _resetTokenRoyalty(tokenId);
    }

    // Override required by Solidity for multiple inheritance
    function supportsInterface(bytes4 interfaceId)
        public
        view
        override(ERC1155, ERC2981)
        returns (bool)
    {
        return super.supportsInterface(interfaceId);
    }
}
```

**Key Features:**

* Default royalty for all tokens.
    
* Optional per-token royalty override.
    
* Easily extensible for batch minting, pausing, access control, etc.
    

### **C. Deploy & Test**

* Deploy to your preferred EVM chain (Ethereum, Polygon, Base, etc.).
    
* Mint tokens to test addresses.
    
* List on OpenSea, Blur, Rarible, and see royalty info show up.
    

### **D. Adding Batch Minting**

```solidity
function mintBatch(address to, uint256[] memory ids, uint256[] memory amounts, bytes memory data) external onlyOwner {
    _mintBatch(to, ids, amounts, data);
}
```

## 5\. Royalties for ERC-721 vs ERC-1155

| Feature | ERC-721 | ERC-1155 |
| --- | --- | --- |
| Token Type | Unique | Semi-fungible/Batchable |
| Use Case | 1/1 Art, PFPs | Editions, Gaming, Tickets |
| Royalty Per Token | Yes | Yes |
| Batch Transfers | No | Yes |
| Default + Per-Token Royalties | Yes | Yes |

**Note:**  
Some marketplaces treat ERC-1155 royalties differently, so always **test every major platform** before launch.

## 6\. Royalty Splitters

Want to split royalties **between multiple wallets or collaborators**? Use [0xSplits](https://www.0xsplits.xyz/) or custom contract logic.

### **A. Using 0xSplits (No-Code)**

1. Set up a split at [0xSplits](https://www.0xsplits.xyz/).
    
2. Get the split contract address.
    
3. Use this address as your royalty receiver in `_setDefaultRoyalty`.
    

### **B. Custom Solidity Splitter Example**

```solidity
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.20;

contract SimpleSplitter {
    address public artist;
    address public dev;
    uint256 public artistShare = 70; // 70%
    uint256 public devShare = 30;    // 30%

    receive() external payable {
        uint256 artistAmount = msg.value * artistShare / 100;
        uint256 devAmount = msg.value - artistAmount;
        payable(artist).transfer(artistAmount);
        payable(dev).transfer(devAmount);
    }
}
```

* Deploy, then set this contract’s address as the royalty receiver.
    

**Pro tip:** For full security and audit-readiness, use established tools like 0xSplits or OpenZeppelin’s PaymentSplitter.

## 7\. Royalty Enforcement Edge Cases & Security Considerations

* **Direct (wallet-to-wallet) transfers bypass royalties.**  
    *You cannot block or charge for a simple “gift” transfer unless you add custom logic—which limits liquidity.*
    
* **Operator filtering is only partly effective.**  
    Blocklists (e.g., OpenSea’s) can be bypassed by new marketplaces.
    
* **Gas griefing:**  
    Complicated royalty logic can raise gas costs. *Always keep functions efficient.*
    
* **Marketplace Upgrades:**  
    Platforms may change how they detect/pay royalties—monitor for changes.
    
* **Immutable Royalties:**  
    You can make royalties unchangeable after deployment for extra trust (but you’ll lose flexibility).
    

## 8\. Testing on OpenSea, Blur, Rarible, Manifold

### **A. OpenSea**

* Supports ERC-2981 (721 & 1155), but royalties may be optional in some collections.
    
* Shows royalty receiver & amount on NFT page.
    
* Can set up royalties via contract or OpenSea UI (be sure to match!).
    

### **B. Blur**

* Focused on traders. Royalties often optional.
    
* If you want Blur to respect royalties, follow their docs and make sure ERC-2981 is present.
    

### **C. Rarible**

* Strong royalty support, with flexible splits.
    
* Supports both contract-level and marketplace-level royalty configs.
    

### **D. Manifold**

* Lets you deploy custom contracts with UI-based royalty settings.
    
* Highly recommended for creators who want more control.
    

### **Testing Steps:**

1. Deploy a contract (testnet/mainnet).
    
2. Mint test NFTs.
    
3. List on each platform.
    
4. Simulate sales. check royalty calculation and distribution.
    
5. Try direct transfers. Verify behavior.
    

## 9\. Monitoring, Analytics, and Automation

**Tools:**

* [Dune Analytics](https://dune.com/): Query royalty payments across chains/collections.
    
* [Reservoir](https://reservoir.tools/): APIs and dashboards for NFT/royalty data.
    
* [Nansen](https://nansen.ai/): Advanced analytics for NFT projects and payments.
    
* **Custom scripts:**  
    Use Ethers.js or [Web3.py](https://web3py.readthedocs.io/en/stable/) to watch for royalty payments to your wallet.
    

**Example using Ethers.js (Node.js):**

```javascript
const { ethers } = require("ethers");
const provider = new ethers.providers.JsonRpcProvider(process.env.RPC_URL);
const royaltyReceiver = "0xYourRoyaltyWalletAddress";

provider.on("block", async () => {
    const balance = await provider.getBalance(royaltyReceiver);
    console.log("Royalty receiver balance:", ethers.utils.formatEther(balance));
});
```

*use event filters to track new sales in real-time!*

## 10\. What’s Next for Royalty Enforcement?

* **Protocol-Level Enforcement:**  
    L2s like Immutable X and new L1s may make on-chain enforcement the default.
    
* **Encrypted/Stealth Transfers:**  
    ZK-tech could make off-market transfers invisible, challenge for royalty collection.
    
* **NFT Utility Models:**  
    Royalties as part of a broader community, access, or revenue share model.
    
* **DAOs for Royalty Distribution:**  
    Automated, on-chain DAOs splitting royalties across hundreds of contributors.
    

## 11\. FAQ

**Q: How do I prevent “wash trading” for royalty farming?**  
*A: Watch for repeated sales between the same addresses at low cost, use analytics to flag suspicious patterns. No foolproof on-chain solution yet.*

**Q: Can I freeze or change royalties after launch?**  
*A: If your contract is “Ownable,” you can change royalties unless you renounce ownership or make the logic immutable. Many advanced projects do this for trust.*

**Q: Can I set different royalties for each NFT or edition?**  
*A: Yes, via ERC-2981’s per-token logic. See setTokenRoyalty example above.*

**Q: How can I distribute royalties to hundreds of addresses?**  
*A: Use splitter contracts (like 0xSplits, PaymentSplitter, or a DAO vault).*
