Posted By : Tushar
NFT royalties are payments made to the original creators each time their digital assets are resold on the secondary market. These payments are automated through smart contracts embedded in blockchain networks using NFT development services , ensuring that creators continue to earn from their work long after the initial sale.
Creators can set their desired royalty percentage during the minting process of the NFT. When a secondary sale occurs, the smart contract automatically allocates the specified percentage of the transaction as a royalty payment to the creator.
One notable example is Beeple's "Crossroads" NFT, which was resold for approximately $6.6 million on the secondary market. Beeple received 10% of the resale value as a royalty payment, demonstrating how NFT royalties provide creators with an ongoing revenue stream.
You may also like | How to Get the Transaction History of an NFT
Despite the visibility gained through social media, artists and creators often struggle to receive fair compensation for their work. Traditional art and content sales typically result in one-time payments, with creators losing control over secondary sales. NFT royalties offer a revolutionary solution by ensuring that creators continue to benefit financially from the resale of their work, providing a sustainable income model and restoring control over how their creations are monetized.
Also, explore | How to Create a Compressed NFT on Solana
To implement the functionality of royalties in smart contracts, we mainly work with two types of smart contracts:
In an ERC-721, every NFT is unique, meaning each NFT must reference its specific content. The ERC-721 standard provides a set of functions that developers can integrate into their smart contracts to create, transfer, and manage NFTs. These functions allow for the creation of unique tokens, each with distinct metadata, making them individually identifiable.
Internally, ERC-721 smart contracts maintain a ledger of token ownership, manage transfers between users, and track the total token supply along with the balance of tokens for each address. A well-known example of an application using the ERC-721 standard is CryptoKitties, a blockchain-based game that allows users to buy, sell, and breed virtual assets. Other examples include Ethermon, MyCrypto, and Cryptodoggies.
Explore more | A Detailed Guide to NFT Minting on Solana using Metaplex API
Here's a sample contract, demonstrating how to integrate royalties functionality to an erc-721 smart contract.
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;
interface IERC721 {
function balanceOf(address owner) external view returns (uint256 balance);
function ownerOf(uint256 tokenId) external view returns (address owner);
function safeTransferFrom(address from, address to, uint256 tokenId) external;
function transferFrom(address from, address to, uint256 tokenId) external;
function approve(address to, uint256 tokenId) external;
function getApproved(uint256 tokenId) external view returns (address operator);
function setApprovalForAll(address operator, bool _approved) external;
function isApprovedForAll(address owner, address operator) external view returns (bool);
}
interface IERC721Receiver {
function onERC721Received(address operator, address from, uint256 tokenId, bytes calldata data) external returns (bytes4);
}
contract ERC721WithRoyalties is IERC721 {
string private _name;
string private _symbol;
mapping(uint256 => address) private _owners;
mapping(address => uint256) private _balances;
mapping(uint256 => address) private _tokenApprovals;
mapping(address => mapping(address => bool)) private _operatorApprovals;
// Royalties mapping: tokenId => (royaltyRecipient, royaltyPercentage)
mapping(uint256 => address) private _royaltyRecipients;
mapping(uint256 => uint256) private _royaltyPercentages;
// Mapping to store token URIs
mapping(uint256 => string) private _tokenURIs;
constructor(string memory name_, string memory symbol_) {
_name = name_;
_symbol = symbol_;
}
// ERC721 Metadata
function name() public view returns (string memory) {
return _name;
}
function symbol() public view returns (string memory) {
return _symbol;
}
function tokenURI(uint256 tokenId) public view returns (string memory) {
require(_exists(tokenId), "ERC721: URI query for nonexistent token");
return _tokenURIs[tokenId];
}
// Function to set token URI
function _setTokenURI(uint256 tokenId, string memory uri) internal {
require(_exists(tokenId), "ERC721: URI set of nonexistent token");
_tokenURIs[tokenId] = uri;
}
// ERC721 Functions
function balanceOf(address owner) public view override returns (uint256) {
require(owner != address(0), "ERC721: balance query for the zero address");
return _balances[owner];
}
function ownerOf(uint256 tokenId) public view override returns (address) {
address owner = _owners[tokenId];
require(owner != address(0), "ERC721: owner query for nonexistent token");
return owner;
}
function approve(address to, uint256 tokenId) public override {
address owner = ownerOf(tokenId);
require(to != owner, "ERC721: approval to current owner");
require(msg.sender == owner || isApprovedForAll(owner, msg.sender), "ERC721: approve caller is not owner nor approved for all");
_tokenApprovals[tokenId] = to;
emit Approval(owner, to, tokenId);
}
function getApproved(uint256 tokenId) public view override returns (address) {
require(_exists(tokenId), "ERC721: approved query for nonexistent token");
return _tokenApprovals[tokenId];
}
function setApprovalForAll(address operator, bool approved) public override {
_operatorApprovals[msg.sender][operator] = approved;
emit ApprovalForAll(msg.sender, operator, approved);
}
function isApprovedForAll(address owner, address operator) public view override returns (bool) {
return _operatorApprovals[owner][operator];
}
function transferFrom(address from, address to, uint256 tokenId) public override {
require(_isApprovedOrOwner(msg.sender, tokenId), "ERC721: transfer caller is not owner nor approved");
_transfer(from, to, tokenId);
}
function safeTransferFrom(address from, address to, uint256 tokenId) public override {
safeTransferFrom(from, to, tokenId, "");
}
function safeTransferFrom(address from, address to, uint256 tokenId, bytes memory _data) public {
require(_isApprovedOrOwner(msg.sender, tokenId), "ERC721: transfer caller is not owner nor approved");
_transfer(from, to, tokenId);
require(_checkOnERC721Received(from, to, tokenId, _data), "ERC721: transfer to non ERC721Receiver implementer");
}
// Internal Functions
function _exists(uint256 tokenId) internal view returns (bool) {
return _owners[tokenId] != address(0);
}
function _isApprovedOrOwner(address spender, uint256 tokenId) internal view returns (bool) {
require(_exists(tokenId), "ERC721: operator query for nonexistent token");
address owner = ownerOf(tokenId);
return (spender == owner || getApproved(tokenId) == spender || isApprovedForAll(owner, spender));
}
function _safeMint(address to, uint256 tokenId, string memory uri) internal {
_mint(to, tokenId);
_setTokenURI(tokenId, uri); // Set the token URI on mint
require(_checkOnERC721Received(address(0), to, tokenId, ""), "ERC721: transfer to non ERC721Receiver implementer");
}
function _mint(address to, uint256 tokenId) internal {
require(to != address(0), "ERC721: mint to the zero address");
require(!_exists(tokenId), "ERC721: token already minted");
_balances[to] += 1;
_owners[tokenId] = to;
emit Transfer(address(0), to, tokenId);
}
function _transfer(address from, address to, uint256 tokenId) internal {
require(ownerOf(tokenId) == from, "ERC721: transfer of token that is not own");
require(to != address(0), "ERC721: transfer to the zero address");
_approve(address(0), tokenId);
_balances[from] -= 1;
_balances[to] += 1;
_owners[tokenId] = to;
emit Transfer(from, to, tokenId);
}
function _approve(address to, uint256 tokenId) internal {
_tokenApprovals[tokenId] = to;
emit Approval(ownerOf(tokenId), to, tokenId);
}
function _checkOnERC721Received(address from, address to, uint256 tokenId, bytes memory _data) private returns (bool) {
if (to.code.length > 0) {
try IERC721Receiver(to).onERC721Received(msg.sender, from, tokenId, _data) returns (bytes4 retval) {
return retval == IERC721Receiver(to).onERC721Received.selector;
} catch {
return false;
}
} else {
return true;
}
}
// Royalty Functions
function setRoyaltyInfo(uint256 tokenId, address recipient, uint256 percentage) external {
require(msg.sender == ownerOf(tokenId), "ERC721: caller is not owner of the token");
require(percentage <= 10000, "ERC721: royalty percentage too high"); // Max 100%
_royaltyRecipients[tokenId] = recipient;
_royaltyPercentages[tokenId] = percentage;
}
function getRoyaltyInfo(uint256 tokenId) external view returns (address recipient, uint256 percentage) {
require(_exists(tokenId), "ERC721: querying royalty info for nonexistent token");
return (_royaltyRecipients[tokenId], _royaltyPercentages[tokenId]);
}
function _calculateRoyalty(uint256 salePrice, uint256 tokenId) internal view returns (uint256) {
uint256 percentage = _royaltyPercentages[tokenId];
return salePrice * percentage / 10000; // Royalty percentage is out of 10000
}
// To be used in conjunction with marketplace integrations
function payRoyalty(uint256 tokenId, uint256 salePrice) external payable {
uint256 royaltyAmount = _calculateRoyalty(salePrice, tokenId);
require(msg.value == royaltyAmount, "ERC721: incorrect royalty payment");
address recipient = _royaltyRecipients[tokenId];
require(recipient != address(0), "ERC721: no recipient set for royalties");
payable(recipient).transfer(msg.value);
}
// Events
event Transfer(address indexed from, address indexed to, uint256 indexed tokenId);
event Approval(address indexed owner, address indexed approved, uint256 indexed tokenId);
event ApprovalForAll(address indexed owner, address indexed operator, bool approved);
}
ERC-1155 is a versatile token standard on the Ethereum blockchain that enables the creation and transfer of both fungible and non-fungible tokens within a single transaction. Combining the features of earlier standards like ERC-20 and ERC-721, it enhances efficiency and significantly reduces costs. This standard supports an infinite variety of tokens, including semi-fungible ones, and offers secure transfer mechanisms without the need to approve each token contract individually.
ERC-1155 allows multiple assets to be managed within a single smart contract, reducing transaction costs and streamlining operations. It enables the transfer of multiple items to one or more recipients in a single transaction. For example, in blockchain games, ERC-1155 simplifies management by integrating various components"”such as shields, swords, and in-game currency"”into a single smart contract, eliminating the need for multiple contracts for each asset.
Also, check | A Step by Step Tutorial of Building a Cross Chain NFT Bridge
Prior to ERC-1155, creating a use case that involved both ERC-20 (fungible) and ERC-721 (non-fungible) tokens required separate contracts for each type. Additionally, ERC-1155 allows for the management of multiple NFT collections within a single smart contract, eliminating the need to create a separate contract for each collection. This consolidation reduces the number of transactions, which is crucial for saving blockchain space and enhancing the efficiency of smart contract deployment.
Consider an online event ticketing system that uses ERC-1155 tokens to manage access to various events. In this system, different token IDs within the smart contract represent various ticket categories, such as general admission, VIP passes, and early bird specials. When users purchase tickets, they receive ERC-1155 tokens corresponding to their chosen ticket type. These tokens are stored in their digital wallets and can be presented at the event for admission. To validate entry, event organizers simply scan the token's QR code.
Also, discover | How to Create a Rentable NFTs
ERC-721 was the first major NFT standard, created in 2017 by the Ethereum development studio ConsenSys, and remains the most popular protocol for NFTs. ERC-1155, a newer standard introduced in 2018 by Enjin, a gaming company specializing in blockchain technology, brought additional flexibility.
ERC-721 tokens are unique and strictly non-fungible, meaning each token is distinct and cannot be interchanged with another. In contrast, ERC-1155 tokens can be fungible, non-fungible, or even semi-fungible. This versatility allows ERC-1155 tokens to represent both collectibles and traditional assets like currencies or commodities.
While both ERC-721 and ERC-1155 are valid standards for NFTs, the key difference is that ERC-721 tokens are always non-fungible, whereas ERC-1155 tokens can be either fungible or non-fungible. ERC-721 is typically preferred for collectibles, while ERC-1155 is favored for use cases involving traditional assets and gaming items due to its efficiency and versatility.
If you are looking to hire NFT developers, explore our large talent pool, comprising skilled full-stack developers.
December 17, 2024 at 08:16 pm
Your comment is awaiting moderation.