Understanding the Problem: Equal Royalties for Unequal NFTs

In some royalty systems, when multiple NFTs are sold together, the royalties may be calculated based on the total sale price, divided equally among all NFTs. This method assumes that all NFTs have the same value, which is often not the case. Consider the following example:

  • NFT 1 is worth 10 ETH.

  • NFT 2 is worth 1 ETH.

If both NFTs are sold together for a total of 11 ETH, and the royalty system splits the royalties equally between both NFTs, both NFT owners would receive the same royalty amount. However, this does not reflect the true value of the assets. The owner of NFT 1 (worth 10 ETH) should receive a much larger portion of the royalties than the owner of NFT 2 (worth 1 ETH).


Real-World Example

Let’s take a closer look at how this problem can occur in smart contracts using Solidity. Consider a contract that calculates royalties for multiple NFTs sold in a single transaction. The following code represents a simplified version of how royalties could be calculated incorrectly:

uint256 totalSalePrice = 11 ether; // Example total sale price
uint256 royaltyPercentage = 10;    // 10% royalties

// Equal distribution of royalties among two NFTs
uint256 royaltyAmountPerNFT = (totalSalePrice * royaltyPercentage) / 100 / 2;

address nftOwner1 = nftOwner1Address; // Owner of the more expensive NFT
address nftOwner2 = nftOwner2Address; // Owner of the cheaper NFT

payRoyalty(nftOwner1, royaltyAmountPerNFT);
payRoyalty(nftOwner2, royaltyAmountPerNFT);

In this case, both NFT owners would receive the same royalty amount, even though one NFT is worth 10 times more than the other. This results in the owner of the more expensive NFT being undercompensated, and the owner of the cheaper NFT being overcompensated.


Proof of Concept: Unfair Royalties

The issue becomes more apparent when we look at a proof of concept. Consider the following scenario:

  • NFT 1 is valued at 10 ETH and NFT 2 is valued at 1 ETH.

  • Both NFTs are sold together for 11 ETH.

  • The royalty percentage is set to 10%.

If royalties are distributed equally between both NFTs:

uint256 totalRoyalty = (11 ether * 10) / 100; // Total royalty = 1.1 ETH
uint256 royaltyPerNFT = totalRoyalty / 2;     // Each NFT gets 0.55 ETH

// Royalty distribution
payRoyalty(nftOwner1, royaltyPerNFT);  // Owner of NFT 1 gets 0.55 ETH
payRoyalty(nftOwner2, royaltyPerNFT);  // Owner of NFT 2 gets 0.55 ETH

In this case, both NFT owners receive 0.55 ETH in royalties, but this distribution is incorrect because the owner of NFT 1, whose NFT is worth 10 times more, should be receiving a much higher share of the royalties.


Impact of Unfair Royalty Calculation

This vulnerability can lead to several negative outcomes:

  1. Loss of Earnings: Owners of high-value NFTs receive fewer royalties than they are entitled to, resulting in a financial loss.

  2. Unfair Distribution: Owners of lower-value NFTs benefit disproportionately from royalties, which is unfair to other participants.

  3. Reduced Trust: If the royalty distribution mechanism is perceived as unfair, it can damage trust in the system, discouraging creators and owners from using the platform.


Mitigation: Calculating Weighted Royalties

To ensure a fair distribution of royalties, the system should calculate royalties based on the relative value of each NFT being sold. This approach involves weighted royalty distribution, where each NFT receives royalties proportionate to its value in the transaction.

Step 1: Track the Value of Each NFT

First, the value of each NFT in the transaction must be known. This could be achieved by keeping track of the sale price for each individual NFT or by using a mechanism that assigns relative weights to NFTs based on their value.

For example:

uint256 nft1Value = 10 ether;  // NFT 1 is worth 10 ETH
uint256 nft2Value = 1 ether;   // NFT 2 is worth 1 ETH

Step 2: Calculate Each NFT's Weight

Calculate the weight of each NFT based on its value relative to the total value of all NFTs in the transaction:

uint256 totalValue = nft1Value + nft2Value;  // Total value = 11 ETH

uint256 nft1Weight = (nft1Value * 1e18) / totalValue;  // Weight of NFT 1
uint256 nft2Weight = (nft2Value * 1e18) / totalValue;  // Weight of NFT 2

Step 3: Distribute Royalties Proportionately

Use the weights to distribute royalties proportionally. The royalties each NFT receives should be based on its weight relative to the total value of the NFTs sold:

uint256 totalRoyalty = (totalSalePrice * royaltyPercentage) / 100;  // Total royalties = 1.1 ETH

// Calculate royalties based on NFT weights
uint256 nft1Royalty = (totalRoyalty * nft1Weight) / 1e18;  // NFT 1 royalty
uint256 nft2Royalty = (totalRoyalty * nft2Weight) / 1e18;  // NFT 2 royalty

payRoyalty(nftOwner1, nft1Royalty);  // Pay NFT 1 owner
payRoyalty(nftOwner2, nft2Royalty);  // Pay NFT 2 owner

In this example:

  • The owner of NFT 1 (worth 10 ETH) would receive approximately 1 ETH in royalties.

  • The owner of NFT 2 (worth 1 ETH) would receive approximately 0.1 ETH in royalties.

This ensures that royalties are distributed fairly based on the actual value of each NFT.


Conclusion

Fair royalty distribution is crucial for maintaining trust and ensuring that participants in a decentralized system receive their due compensation. The use of exact balance checks or equal distribution of royalties can lead to vulnerabilities where high-value NFTs are undercompensated, while low-value NFTs are overcompensated.

By using weighted royalty distribution based on the relative value of NFTs, developers can ensure that royalties are calculated fairly and accurately, preventing potential loss of earnings and ensuring a more equitable system for all participants.srupt the normal operation of the contract by causing balance checks to fail. This could lock users out from critical functions such as staking, minting, or withdrawing tokens.

  1. Loss of Functionality: Legitimate users may be unable to interact with the contract, preventing them from participating in key operations like claiming rewards, transferring tokens, or executing transactions.

  2. Security Concerns: If the balance check is used as a form of security validation, attackers could bypass these checks by artificially modifying the contract's token balance, undermining the integrity of the system.


Mitigation Strategies

To protect contracts from this vulnerability, developers should avoid using exact balance comparisons.

Last updated