How not to enforce NFT Royalties: A Tutorial for Artists

This tutorial explains a smart contract with a Harberger tax concept for Ethereum based chains.

February 19, 2023

How not to enforce NFT Royalties: A Tutorial for Artists

NFTs, or non-fungible tokens, are a unique type of digital asset that can represent anything from art and music to video games and virtual real estate. With the rise of NFTs, creators now have a new way to monetize their work by selling it as a unique digital asset. However, unlike physical artwork, it can be difficult to enforce royalties on NFTs. In this tutorial, we will discuss how to use Harberger tax instead of royalties.

A Harberger tax is a tax system that requires individuals or companies to self-assess the value of their assets and then pay a tax on that assessed value. The unique aspect of the Harberger tax is that the taxpayer is required to make the tax payment even if they are not willing to sell the asset. This tax system is designed to incentivize the efficient use of assets and to prevent underutilization of resources.

A royalty is a payment made to the owner of a property or asset in exchange for the use of that asset. In the context of NFTs, a royalty is typically a percentage of the sale price that the owner of the NFT receives each time the NFT is sold.

Combining these concepts, a Harberger tax on NFT royalties would require NFT owners to self-assess the value of their NFTs and pay a tax on that assessed value. Additionally, the tax would be ongoing, requiring the owner to pay a percentage of the royalties they receive each time the NFT is sold. This could potentially incentivize more efficient use of NFTs and prevent underutilization of these unique digital assets.

Basically, it's like this, you sell a deed, you pay a tax. The longer you hold onto the deed, the more tax you pay. And get this, the contract is gonna keep track of all the taxes you owe and collect it whenever it wants from your prepaid balance.

But here's the kicker, instead of having a separate balance for each deed you own (which would be difficult to implement), the contract keeps track of your total balance for all your deeds. That way, you can just deposit into one balance like a boss and call it a day.

And if you're thinking, "Well, how does the contract know how much tax I owe?" It just looks at the total sales price of all your deeds and when you paid your taxes last.

Let's take a look at a simple example of how to create Harberger tax logic using the ERC-721 standard. In this example, we'll create a smart contract that represents a digital art piece.

pragma solidity ^0.8.0;

import "@openzeppelin/contracts/token/ERC721/ERC721.sol";

contract HarbergerNFT is ERC721 {
    // Define NFT ownership structure
    struct NFT {
        address owner;
        uint256 value;
        uint256 royalty;
        bool forSale;
    // Mapping to track NFT ownership
    mapping (uint256 => NFT) public NFTs;
    // Harberger tax rate in percent (e.g. 5%)
    uint256 public harbergerTaxRate = 5;
    constructor(string memory name, string memory symbol) ERC721(name, symbol) {}
    // Function to buy an NFT
    function buyNFT(uint256 tokenId) public payable {
        // Check that NFT is for sale
        require(NFTs[tokenId].forSale == true, "NFT not for sale");
        // Calculate purchase price
        uint256 purchasePrice = NFTs[tokenId].value + (NFTs[tokenId].value * NFTs[tokenId].royalty / 100);
        // Apply Harberger tax
        uint256 harbergerTax = (NFTs[tokenId].value * harbergerTaxRate / 100);
        NFTs[tokenId].value += harbergerTax;
        // Transfer NFT ownership
        _transfer(NFTs[tokenId].owner, msg.sender, tokenId);
        // Update NFT ownership and forSale status
        NFTs[tokenId].owner = msg.sender;
        NFTs[tokenId].forSale = false;
        // Send payment to previous owner
        payable(NFTs[tokenId].owner).transfer(purchasePrice - harbergerTax);
    // Function to sell an NFT
    function sellNFT(uint256 tokenId, uint256 salePrice) public {
        // Check that caller is NFT owner
        require(msg.sender == NFTs[tokenId].owner, "Caller is not NFT owner");
        // Update NFT value and forSale status
        NFTs[tokenId].value = salePrice;
        NFTs[tokenId].forSale = true;
    // Function to set the Harberger tax rate
    function setHarbergerTaxRate(uint256 newTaxRate) public {
        // Check that caller is contract owner
        require(msg.sender == owner(), "Caller is not contract owner");
        // Update tax rate
        harbergerTaxRate = newTaxRate;

In this contract, the ERC721 standard is inherited and the NFT ownership structure is defined in a struct that includes the owner address, the current value of the NFT, the royalty percentage, and a boolean forSale flag indicating whether the NFT is currently available for purchase. The contract includes functions for buying and selling NFTs, with the purchase price calculated as the NFT value plus the royalty percentage, and the Harberger tax calculated as the value multiplied by the Harberger tax rate. The contract owner can also set the Harberger tax rate using the setHarbergerTaxRate function.

If you want to find out more on how to create your NFT with a Harberger tax instead of royalties contact us

inspired by: Arthur B. twitter thread This Artwork is Always For Sale Todd Proebsting