Free 30-min Web3 Consultation
Book Consultation
Smart Contract Security Audits
View Audit Services
Custom DeFi Protocol Development
Explore DeFi
Full-Stack Web3 dApp Development
View App Services
Free 30-min Web3 Consultation
Book Consultation
Smart Contract Security Audits
View Audit Services
Custom DeFi Protocol Development
Explore DeFi
Full-Stack Web3 dApp Development
View App Services
Free 30-min Web3 Consultation
Book Consultation
Smart Contract Security Audits
View Audit Services
Custom DeFi Protocol Development
Explore DeFi
Full-Stack Web3 dApp Development
View App Services
Free 30-min Web3 Consultation
Book Consultation
Smart Contract Security Audits
View Audit Services
Custom DeFi Protocol Development
Explore DeFi
Full-Stack Web3 dApp Development
View App Services
LABS
Guides

How to Implement Dynamic Royalty Models

This guide provides a technical walkthrough for implementing dynamic royalty logic in NFT smart contracts. It covers the EIP-2981 standard, conditional rate changes, and practical code for time-based, volume-based, and holder-based royalty models.
Chainscore © 2026
introduction
SMART CONTRACT GUIDE

How to Implement Dynamic Royalty Models

A technical guide for developers to implement flexible, on-chain royalty logic that can adjust fees based on market conditions, time, or sales volume.

Dynamic royalty models move beyond the static, fixed-percentage fees common in early NFT standards like ERC-2981. Instead, they allow the royalty amount to be calculated programmatically at the time of sale. This enables creators to implement strategies such as time-decaying fees, volume-based discounts, or tiered pricing based on the sale price. The core logic is embedded directly in the smart contract, making the royalty calculation transparent and trustless. This guide will walk through implementing a basic dynamic royalty system using Solidity for an ERC-721 or ERC-1155 contract.

The foundation for any on-chain royalty system is the royaltyInfo function, as defined by the ERC-2981 standard. This function takes a tokenId and salePrice as inputs and returns the receiver address and the royaltyAmount. For a dynamic model, you replace a simple percentage multiplication with a custom calculation. For example, a contract could implement a decaying royalty that starts at 10% and reduces by 1% every 30 days after the initial mint. The calculation would check the block timestamp against a stored mint time for the token.

Here is a simplified code snippet for a time-based decaying royalty model. This example assumes the contract stores a mintTimestamp for each token ID.

solidity
function royaltyInfo(uint256 tokenId, uint256 salePrice)
    external
    view
    override
    returns (address receiver, uint256 royaltyAmount)
{
    receiver = royaltyReceiver;
    uint256 elapsedDays = (block.timestamp - mintTimestamp[tokenId]) / 1 days;
    // Start at 1000 basis points (10%), decrease by 100 bps (1%) every 30 days
    uint256 royaltyBps = 1000 - ((elapsedDays / 30) * 100);
    // Enforce a minimum royalty of 2.5%
    if (royaltyBps < 250) royaltyBps = 250;
    royaltyAmount = (salePrice * royaltyBps) / 10000;
}

This logic is executed on-chain during the sale, ensuring the royalty is always calculated correctly based on current conditions.

More complex models can be built by incorporating other on-chain data. A volume-tiered model could query the total sales volume for a specific buyer or collection and offer a reduced royalty for high-volume traders. An auction-style model could implement a Dutch auction for the royalty percentage itself, starting high and decreasing until a sale occurs. These models require careful design to avoid gas inefficiency and ensure the royaltyInfo function remains a view function (if possible) to be compatible with marketplaces that call it off-chain for price estimation.

When implementing dynamic royalties, key considerations include gas costs, marketplace compatibility, and transparency. While major marketplaces like OpenSea and Blur support ERC-2981, excessively complex logic may lead to high gas fees or off-chain integration issues. It is crucial to document the royalty logic clearly for users. Furthermore, immutable logic locked in a contract cannot be updated, so consider using an upgradeable proxy pattern or a configurable controller contract if future adjustments might be necessary. Always audit your royalty logic thoroughly to prevent exploits or unintended financial outcomes.

prerequisites
FOUNDATIONAL KNOWLEDGE

Prerequisites

Before implementing a dynamic royalty model, you need a solid understanding of the core blockchain and smart contract concepts that make it possible.

A dynamic royalty model is a smart contract that programmatically adjusts the royalty fee paid to creators based on predefined logic. This is a significant evolution from the static, hardcoded fees used in standards like ERC-2981. To build one, you must first be proficient in a smart contract language like Solidity (for Ethereum, Polygon, Avalanche) or Rust (for Solana). You should understand core concepts such as state variables, functions, modifiers, and inheritance. Familiarity with development tools like Hardhat, Foundry, or Anchor is essential for writing, testing, and deploying your contracts.

You must also understand the token standards your model will interact with. For Ethereum Virtual Machine (EVM) chains, this is typically ERC-721 for NFTs or ERC-1155 for multi-token contracts. Your royalty contract will need to implement the royaltyInfo function as defined in ERC-2981, returning the recipient address and royalty amount. For dynamic logic, you'll override this function to calculate the fee based on your chosen parameters, such as sale price, time since mint, or holder status.

Finally, grasp the transaction lifecycle. Royalties are enforced at the marketplace level during a sale. Marketplaces like OpenSea, Blur, and LooksRare call the royaltyInfo function on your NFT's smart contract. Your dynamic contract must return the calculated fee, which the marketplace then sends to your designated royalty recipient. This requires your contract's logic to be gas-efficient and deterministic, as it executes on-chain during every sale. Testing with forked mainnet environments using tools like Alchemy or Infura is crucial to simulate real-world conditions before deployment.

eip-2981-foundation
ROYALTY STANDARD

The Foundation: EIP-2981 Standard

EIP-2981 defines a universal interface for on-chain royalty information, enabling dynamic and interoperable royalty models for NFTs across marketplaces and applications.

Prior to EIP-2981, NFT royalty enforcement was fragmented and unreliable. Marketplaces implemented proprietary, off-chain systems, and creators had no standard way to communicate their royalty expectations to smart contracts. This led to royalty bypassing, inconsistent payouts, and a lack of interoperability. EIP-2981 solves this by introducing a simple, backward-compatible royaltyInfo function that any NFT contract can implement. This function returns the royalty recipient address and the amount owed for a given sale price, providing a single source of truth that marketplaces can query.

The core of EIP-2981 is a single function interface: function royaltyInfo(uint256 tokenId, uint256 salePrice) external view returns (address receiver, uint256 royaltyAmount). The tokenId parameter allows for per-token royalty configurations, enabling dynamic models where royalties can vary based on the specific NFT. The salePrice is the final sale price (in the transaction's native currency, like ETH), and the function calculates the royalty amount. This design is gas-efficient for read calls and provides the flexibility needed for complex royalty logic, such as tiered rates or time-based decays.

Implementing EIP-2981 is straightforward. For a basic, fixed-rate royalty across a collection, you can store the recipient and basis points (e.g., 750 for 7.5%) in your contract's storage. The royaltyInfo function then calculates the amount: royaltyAmount = (salePrice * royaltyBps) / 10000. For more advanced models, the logic within this function can pull data from a mapping keyed by tokenId or execute custom calculations. Major marketplaces like OpenSea, Blur, and LooksRare support this standard, automatically routing payments to the address returned by this function.

Dynamic royalty models unlock new creator economies. You can program royalties to decrease after a certain number of trades, increase if the NFT is part of a rare set, or even route a percentage to a community treasury automatically. Because the logic is on-chain and standardized, these rules are enforced uniformly. This transforms royalties from a static fee into a programmable component of the NFT's utility, enabling use cases like patronage models where early supporters get a share of future sales or collaborative splits between multiple artists on a single piece.

When implementing, consider gas optimization and upgrade paths. Storing royalty data in a packed storage slot or using an immutable variable for a global rate reduces deployment and read costs. For future-proofing, consider using a proxy pattern or a dedicated RoyaltyManager contract that your NFT mints point to, allowing you to update logic without redeploying the entire collection. Always verify your implementation using tools like the Royalty Registry and test integration with marketplace testnets to ensure correct payout behavior before mainnet deployment.

dynamic-model-types
IMPLEMENTATION GUIDE

Types of Dynamic Royalty Models

Dynamic royalty models allow creators to programmatically adjust fees based on market conditions or user behavior. This guide covers the primary on-chain implementation patterns.

03

Holder-Based Royalty Discounts

Reduce or waive royalties for transactions between wallets that have held the NFT for a specified period. This encourages long-term holding and reduces friction for true community members.

Implementation Details:

  • The royalty contract must check the seller's balanceOf duration for the specific token ID.
  • A common pattern is to use a staking mechanism or a snapshot of transfer timestamps.
  • Projects like Art Blocks have explored models where royalties are 0% for transfers between wallets holding >90 days.
time-based-implementation
SMART CONTRACT GUIDE

Implementing Time-Based Royalties

A technical guide to building dynamic royalty models that change automatically based on time, event milestones, or other on-chain conditions.

Time-based royalties are a mechanism where the royalty fee for an NFT or digital asset changes according to a predefined schedule. Unlike static royalties, which are fixed at minting, dynamic models can increase to reward early collectors, decrease to boost secondary sales, or shift based on external triggers. This is implemented using smart contracts that contain the logic to calculate the current royalty rate, often referencing a public variable like block.timestamp or a specific on-chain event counter. The ERC-2981 standard provides a foundation for implementing these programmable royalty systems.

The core implementation involves overriding the royaltyInfo function. A basic structure stores a schedule—for example, an array of timestamps and corresponding fee numerators. When royaltyInfo is called, the contract checks the current block timestamp against the schedule to determine the active rate. Here's a simplified Solidity snippet:

solidity
function royaltyInfo(uint256, uint256 salePrice) public view override returns (address, uint256) {
    uint256 fee;
    if (block.timestamp < phaseOneEnd) {
        fee = (salePrice * 1000) / 10000; // 10%
    } else {
        fee = (salePrice * 500) / 10000; // 5%
    }
    return (royaltyReceiver, fee);
}

This model creates a decaying royalty, incentivizing early adoption with a higher creator fee that later reduces to encourage liquidity.

More advanced models can tie royalties to on-chain milestones rather than just time. For instance, the royalty rate could decrease after the 100th secondary sale (tracked via a counter), or increase if the asset is sold on a specific marketplace. You can also integrate with oracles like Chainlink to use real-world data, such as adjusting fees based on the asset's performance in an external game or metrics platform. This requires careful design to avoid gas inefficiency and ensure the royaltyInfo function remains a view function for compatibility with marketplaces.

When deploying time-based royalties, key considerations include upgradeability and transparency. Since the schedule is logic embedded in the contract, it cannot be easily changed post-deployment unless using a proxy pattern. The schedule should be clearly documented and verifiable on-chain to maintain collector trust. Major marketplaces like OpenSea and Blur that support ERC-2981 will read the fee directly from your contract, but you must test integration thoroughly. Dynamic royalties represent a shift towards more sophisticated and fair economic models for digital assets.

volume-based-implementation
ADVANCED NFT MECHANICS

Implementing Volume-Based Royalties

A technical guide to designing and deploying dynamic royalty models that adjust fees based on secondary market sales volume.

Traditional NFT royalties apply a fixed percentage to every secondary sale, a model increasingly circumvented by marketplaces. A volume-based royalty introduces a dynamic fee structure where the royalty rate changes based on the cumulative sales volume of a specific token. This creates powerful incentives: rewarding long-term holders and high-volume traders with lower fees, while applying a standard or higher rate to initial or low-volume sales. This model aligns creator revenue with genuine market activity and holder loyalty, moving beyond the one-size-fits-all approach.

Implementing this requires a custom smart contract that tracks sales volume per token. The core logic involves overriding the royaltyInfo function specified by standards like EIP-2981. Instead of returning a static fee, the function must calculate the fee based on the token's historical volume. You need an on-chain data structure, typically a mapping like mapping(uint256 => uint256) private _volumeAccrued;, which updates with the sale price on each transfer. A common pattern is to use a tiered system: e.g., 10% fee for the first 1 ETH in volume, 5% for volume between 1 and 10 ETH, and 2.5% for all volume thereafter.

Here is a simplified Solidity snippet demonstrating the key components:

solidity
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.19;
import '@openzeppelin/contracts/token/common/ERC2981.sol';
contract VolumeRoyaltyNFT is ERC721, ERC2981 {
    mapping(uint256 => uint256) public volumeAccrued;
    
    function royaltyInfo(uint256 tokenId, uint256 salePrice)
        public view override
        returns (address receiver, uint256 royaltyAmount)
    {
        receiver = royaltyReceiver;
        uint256 volume = volumeAccrued[tokenId];
        uint256 rate;
        
        if (volume < 1 ether) rate = 1000; // 10%
        else if (volume < 10 ether) rate = 500; // 5%
        else rate = 250; // 2.5%
        
        royaltyAmount = (salePrice * rate) / 10000;
    }
    
    function _update(address to, uint256 tokenId, address auth)
        internal virtual override returns (address)
    {
        // Update volume tracking logic here on sale
        address from = _ownerOf(tokenId);
        if (from != address(0) && to != address(0) && msg.value > 0) {
            volumeAccrued[tokenId] += msg.value;
        }
        return super._update(to, tokenId, auth);
    }
}

Note: This is a conceptual example; a production contract requires secure payment handling and integration with a marketplace's transfer logic.

Key design considerations include gas efficiency for volume lookups, ensuring compatibility with major marketplaces that support EIP-2981, and defining clear, transparent tier thresholds. The update mechanism must be secured to only increment volume on genuine sales, typically within an overridden _update or _afterTokenTransfer hook. Off-chain indexing services like The Graph can be crucial for efficiently querying an NFT's lifetime volume for display in frontends, as on-chain historical calculations can be gas-intensive for applications.

Use cases extend beyond simple tiering. Models can incorporate time decay, where the royalty rate decreases the longer a token is held, or bonus rates for sales occurring on preferred marketplaces. The flexibility allows for programmable royalty streams that can react to market conditions. However, complexity introduces risk; thorough testing with tools like Foundry or Hardhat is essential to audit the financial logic and prevent exploits in the volume tracking or fee calculation.

Ultimately, volume-based royalties represent a shift towards more sophisticated and fair creator economics. By moving away from static fees, creators can design systems that incentivize specific trading behaviors while adapting to an ecosystem where royalty enforcement is not guaranteed. Successful implementation requires careful smart contract design, a clear understanding of the EIP-2981 standard, and integration planning with secondary market platforms.

holder-based-implementation
TUTORIAL

Implementing Holder-Based Royalties

A technical guide to building dynamic NFT royalty models that reward long-term holders and community members.

Holder-based royalties are a dynamic fee model where the royalty percentage paid to a creator on secondary sales changes based on the current owner's status. Unlike static royalties, which apply a flat fee (e.g., 5%) to every sale, dynamic models can incentivize specific behaviors. Common implementations offer reduced royalty rates for verified long-term holders or members of a specific community, effectively creating a loyalty discount. This approach can help combat royalty evasion by making compliance more attractive and fosters a stronger bond between creators and their core collector base.

The core mechanism relies on checking the buyer's or seller's wallet address against a set of on-chain conditions before calculating the fee. In the ERC-2981 royalty standard, the royaltyInfo function is called during a transfer. A smart contract implementing holder-based logic would override this function. It first checks if the involved address (often the receiver or msg.sender) is eligible—for instance, by verifying token ownership duration via a snapshot or checking membership in a whitelist. The function then returns a custom royalty amount and recipient address based on the result.

Here is a simplified Solidity example extending ERC-2981. It uses a mapping to store whitelisted addresses eligible for a reduced fee.

solidity
import "@openzeppelin/contracts/token/common/ERC2981.sol";

contract HolderRoyaltyNFT is ERC721, ERC2981 {
    uint96 public constant STANDARD_FEE = 750; // 7.5%
    uint96 public constant HOLDER_FEE = 250;   // 2.5%
    mapping(address => bool) public holderWhitelist;

    function royaltyInfo(
        uint256 tokenId,
        uint256 salePrice
    ) public view override returns (address receiver, uint256 royaltyAmount) {
        receiver = ownerOf(tokenId); // Creator/DAO treasury
        uint96 feeBasisPoints = STANDARD_FEE;
        // Check if the seller (transaction caller) is a whitelisted holder
        if (holderWhitelist[msg.sender]) {
            feeBasisPoints = HOLDER_FEE;
        }
        royaltyAmount = (salePrice * feeBasisPoints) / 10000;
    }
}

This contract applies a 7.5% standard royalty but only charges 2.5% if the seller is on the holderWhitelist.

Implementing a robust system requires careful design. The whitelist in the example is simplistic; a production system needs a secure way to manage it, often via a privileged admin or a decentralized governance vote. A more advanced model might calculate holding time on-chain. This can be done by recording the block timestamp when a user acquires a token and comparing it to the current block timestamp during a sale. However, this increases gas costs and complexity. Alternatively, you can use off-chain snapshots and merkle proofs for verification, a method employed by projects like Manifold's Royalty Registry for efficient whitelist updates.

When deploying holder-based royalties, consider the marketplace compatibility. While ERC-2981 is widely supported, not all marketplaces fully honor custom logic within the royaltyInfo function. It's crucial to test integration with major platforms like OpenSea, Blur, and LooksRare. Furthermore, clear communication is essential. Transparency about how discounts are earned (e.g., "Hold for 30 days for a reduced 2% fee") builds trust. This model shifts the focus from enforcement to incentive, aligning the economic interests of creators, loyal collectors, and the secondary market platforms themselves.

IMPLEMENTATION APPROACHES

Dynamic Royalty Model Comparison

A comparison of common methods for implementing dynamic royalties on-chain, detailing their technical characteristics and trade-offs.

Feature / MetricOracle-BasedOn-Chain LogicHybrid (Off-Chain + On-Chain)

Update Trigger

External oracle data feed

Pre-programmed on-chain conditions

Off-chain indexer with on-chain settlement

Update Frequency

Real-time to daily

Fixed intervals (e.g., per block)

On-demand via signed message

Gas Cost for Update

High (oracle call + logic)

Low (pure computation)

Medium (signature verification)

Decentralization

Depends on oracle security

Fully decentralized

Semi-decentralized

Flexibility

High (any external data)

Limited (pre-defined rules only)

High (off-chain logic)

Implementation Complexity

Medium

Low

High

Royalty Enforcement Guarantee

High (if oracle is trusted)

High

Conditional (relies on off-chain component)

Example Protocols

Chainlink, Pyth

Native smart contract logic

EIP-712 signed messages, OpenSea

security-considerations
DYNAMIC ROYALTIES

Security and Design Considerations

Implementing on-chain royalty logic requires careful planning for security, gas efficiency, and upgradeability. These guides cover the core technical considerations.

01

Royalty Enforcement Architectures

Choosing the right enforcement mechanism is foundational. Marketplace-level enforcement relies on operator compliance, while on-chain enforcement uses smart contract logic.

  • Pull vs. Push Payments: A pull model (e.g., EIP-2981) calculates royalties on-demand, while a push model (e.g., Manifold's Royalty Engine) distributes them atomically on sale.
  • Security Trade-offs: On-chain enforcement prevents bypass but increases gas costs and complexity. Off-chain enforcement is gas-efficient but requires trust in marketplace operators.
02

Preventing Royalty Bypass

A primary security risk is users circumventing royalty payments via direct peer-to-peer transfers or custom sale contracts.

  • Transfer Validation: Implement a modifier like _beforeTokenTransfer to check if a sale is occurring and validate payment routing.
  • Marketplace Allowlists: Use an upgradable registry (e.g., a mapping) to approve specific marketplace contracts, rejecting sales from unauthorized venues.
  • Example: The 0xSplits royalty contract validates that the msg.sender is an approved marketplace before releasing funds to the seller.
03

Gas Optimization Strategies

Dynamic logic can become expensive. Optimize for the common case.

  • Caching & Storage Layout: Store frequently accessed royalty parameters (recipient, basis points) in packed storage slots to minimize SSTORE operations.
  • Lazy Computation: Compute complex tiered royalty splits off-chain and pass them as signed parameters for on-chain verification, reducing gas for the buyer.
  • Stateless vs. Stateful: A stateless design using EIP-2981 returns data without writing to storage, costing ~5k gas. A stateful engine that splits funds costs 50k+ gas.
04

Upgradeability and Admin Controls

Royalty parameters will need updates. Design secure admin functions.

  • Multi-sig & Timelocks: Use a multi-signature wallet (e.g., Safe) for privileged functions like changing the royalty recipient or basis points. Implement a timelock for critical changes.
  • Upgrade Patterns: For complex logic, use a Transparent Proxy or UUPS pattern to upgrade the royalty engine without migrating the NFT contract.
  • Role-Based Access: Implement OpenZeppelin's AccessControl to define distinct roles for updating parameters vs. pausing the contract.
05

Testing Royalty Logic

Comprehensive testing is critical for financial logic. Use a dedicated test suite.

  • Fork Testing: Use Foundry's cheatcodes to fork Mainnet and test against live marketplace contracts (e.g., Seaport, Blur).
  • Edge Cases: Test zero-value transfers, sales through unapproved marketplaces, and royalty sums that exceed 100%.
  • Integration Tests: Simulate full sale flows using the Ethier library for fuzzing or Chainlink VRF for random tier assignments to ensure robustness.
testing-and-verification
TESTING AND ON-CHAIN VERIFICATION

How to Implement Dynamic Royalty Models

A guide to designing, deploying, and verifying smart contracts for NFT royalties that can change based on market conditions or time.

Dynamic royalty models allow NFT creators to adjust the royalty fee percentage after minting, based on programmable logic. Unlike static royalties hardcoded at deployment, dynamic models can respond to triggers like secondary sale price, time since mint, or holder count. This is typically implemented using the RoyaltyInfo function from standards like EIP-2981, where the return value is calculated by an internal function instead of a fixed variable. The primary challenge is ensuring the on-chain logic is gas-efficient, secure, and behaves as intended across all edge cases, which necessitates rigorous testing and verification.

Start by writing the core logic in a separate, testable library or internal function. For example, a model might reduce the royalty from 10% to 5% after a specific block timestamp or if the sale price exceeds 10 ETH. Use Foundry or Hardhat to create a comprehensive test suite. Key tests should include: verifying the correct royalty is returned for different sale prices, ensuring only the owner or a designated manager can update configuration parameters, and checking that the function reverts for unauthorized calls. Test for edge cases like zero addresses, zero sale prices, and maximum integer values to prevent overflows.

After testing, the next step is on-chain verification. Deploy the contract to a testnet like Sepolia or Goerli first. Use a block explorer like Etherscan to verify and publish the source code, which allows anyone to audit the royaltyInfo logic. For dynamic models, consider implementing a time-locked upgrade mechanism for the royalty logic using a proxy pattern (like Transparent or UUPS) or a dedicated configuration contract. This ensures you can fix bugs or adjust parameters without disrupting the NFT collection. Always simulate the upgrade process on a testnet to ensure state is preserved and the new logic integrates correctly.

Monitoring is crucial post-deployment. Tools like Tenderly or OpenZeppelin Defender can create alerts for failed transactions or deviations from expected royalty payments. For fully on-chain dynamic models, consider emitting specific events (e.g., RoyaltyUpdated) when the fee changes, making it easier for indexers and marketplaces to track. Remember that while EIP-2981 is widely supported, marketplace compliance is not universal; major platforms like OpenSea and Blur read this standard, but custom logic should include a fallback mechanism or clear documentation for integrators.

Finally, consider the user experience and gas implications. Complex on-chain calculations for every royaltyInfo call can become expensive for buyers and sellers. Optimize by using storage variables for configuration and performing minimal computation in the read function. For advanced models, an off-chain component can compute the royalty and have it signed by the creator, with the contract verifying the signature—though this adds centralization. The choice depends on the trade-off between flexibility, cost, and decentralization required for your specific use case.

DYNAMIC ROYALTIES

Frequently Asked Questions

Common developer questions and troubleshooting for implementing on-chain royalty models that adapt to market conditions.

A dynamic royalty model is a smart contract mechanism where the royalty fee percentage paid to creators or a protocol is not fixed. Instead, it changes automatically based on predefined on-chain logic and market conditions.

Key differences from static models:

  • Static Royalties: A fixed percentage (e.g., 5%) hardcoded into the NFT contract, often using the EIP-2981 standard.
  • Dynamic Royalties: The fee adjusts according to rules. For example, the royalty might:
    • Decrease over time to encourage long-term trading.
    • Increase for high-value sales above a certain threshold.
    • Fluctuate based on the holding period or the trading volume of a collection.

Implementation requires custom logic in the royalty function (royaltyInfo in EIP-2981) that reads from oracles, timestamps, or internal state variables to calculate the current rate.