Creating a Smart Contract with NFT Royalties

Creating a Smart Contract with NFT Royalties
6 min read

NFTs are unique tokens created on blockchain networks that verify the originality of digital assets. Ethereum’s [plate_number_3] standard is the preferred choice for creating NFTs, providing a robust framework of rules and interfaces for seamless interoperability. Smart contracts built using [plate_number_3] adhere to mandatory functions, including creating new tokens, transferring token ownership, and providing critical metadata.

To expedite the development of ERC721 contracts, you can leverage the OpenZeppelin library, a cornerstone of smart contract development services. OpenZeppelin is a reputable open-source platform that offers audited, secure, and frequently updated smart contract libraries. These libraries encompass popular Solidity standards such as ERC20 and ERC721, in addition to libraries for access control, payments, and security.

OpenZeppelin’s community-driven approach ensures robustness and security for NFTs, with optional extensions like Metadata and URIStorage. The ERC2981 standard offers a standardized way to implement royalties for NFTs, enabling owners to earn royalties on secondary market sales. Smart contract development companies can help navigate NFT standards, ensuring compliance, security, and functionality. For more on ERC token standards and NFTs, explore further resources and guides.

Creating an NFT Smart Contract for Royalty Solution

// SPDX-License-Identifier: MIT

pragma solidity ^0.8.0;

import “@openzeppelin/contracts/token/interfaces/IERC2981.sol”;

import “@openzeppelin/contracts/token/utils/introspection/ERC165.sol”;

abstract contract ERC2981 is IERC2981, ERC165 {

struct RoyaltyInfo {

address receiver;

uint96 royaltyFraction;

}

RoyaltyInfo private _defaultRoyaltyInfo;

mapping(uint256 => RoyaltyInfo) private _tokenRoyaltyInfo;

function supportsInterface(bytes4 interfaceId) public view virtual override(IERC165, ERC165) returns (bool) {

return interfaceId == type(IERC2981).interfaceId || super.supportsInterface(interfaceId);

}

function royaltyInfo(uint256 tokenId, uint256 salePrice) public view virtual override returns (address, uint256) {

RoyaltyInfo memory royalty = _tokenRoyaltyInfo[tokenId];

if (royalty.receiver == address(0)) {

royalty = _defaultRoyaltyInfo;

}

uint256 royaltyAmount = (salePrice * royalty.royaltyFraction) / _feeDenominator();

return (royalty.receiver, royaltyAmount);

}

function _feeDenominator() internal pure virtual returns (uint96) {

return 10000;

}

function _setDefaultRoyalty(address receiver, uint96 feeNumerator) internal virtual {

require(feeNumerator <= _feeDenominator(), “ERC2981: royalty fee will exceed salePrice”);

require(receiver != address(0), “ERC2981: invalid receiver”);

_defaultRoyaltyInfo = RoyaltyInfo(receiver, feeNumerator);

}

function _deleteDefaultRoyalty() internal virtual {

delete _defaultRoyaltyInfo;

}

function _setTokenRoyalty(uint256 tokenId, address receiver, uint96 feeNumerator) internal virtual {

require(feeNumerator <= _feeDenominator(), “ERC2981: royalty fee will exceed salePrice”);

require(receiver != address(0), “ERC2981: Invalid parameters”);

_tokenRoyaltyInfo[tokenId] = RoyaltyInfo(receiver, feeNumerator);

}

function _resetTokenRoyalty(uint256 tokenId) internal virtual {

delete _tokenRoyaltyInfo[tokenId];

}

}

The royalty recipient's details and the percentage of the sale price that the royalty reflects are both contained in the contract's RoyaltyInfo struct. The contract also includes two variables: _tokenRoyaltyInfo, which maps token IDs to their unique royalty information, and _defaultRoyaltyInfo, which represents the default royalty information for all tokens.

The contract implements the IERC2981 interface, which requires the implementation of a royaltyInfo function that returns the royalty information for a given token ID and sale price. The implementation first checks if there is specific royalty information for the given token ID and if not, it uses the default royalty information. It then calculates the royalty amount based on the sale price and the royalty fraction and returns the royalty recipient and amount.

The contract also has four internal functions: _feeDenominator, _setDefaultRoyalty, _deleteDefaultRoyalty, and _setTokenRoyalty. _feeDenominator returns the denominator with which to interpret the royalty fraction as a fraction of the sale price. By default, it returns 10000, meaning the royalty fee is specified in basis points. _setDefaultRoyalty sets the default royalty information for all tokens. _deleteDefaultRoyalty removes the default royalty information. _setTokenRoyalty sets the royalty information for a specific token ID, overriding the global default.

// SPDX-License-Identifier: MIT

pragma solidity ^0.8.4;

import “@openzeppelin/contracts/token/common/ERC2981.sol”;

import “@openzeppelin/contracts/token/ERC721/extensions/ERC721URIStorage.sol”;

import “@openzeppelin/contracts/access/Ownable.sol”;

import “@openzeppelin/contracts/utils/Counters.sol”;

contract NFT is ERC721URIStorage, ERC2981, Ownable {

using Counters for Counters.Counter;

Counters.Counter private _tokenIds;

constructor(string memory _name, string memory _symbol) ERC721(_name, _symbol) {

_setDefaultRoyalty(msg.sender, 100);

}

function _burn(uint256 tokenId) internal virtual override {

super._burn(tokenId);

_resetTokenRoyalty(tokenId);

}

function burn(uint256 tokenId)

public onlyOwner {

_burn(tokenId);

}

function mint(address recipient, string memory tokenURI)

public onlyOwner

returns (uint256) {

_tokenIds.increment();

uint256 newItemId = _tokenIds.current();

_safeMint(recipient, newItemId);

_setTokenURI(newItemId, tokenURI);

return newItemId;

}

function mintWithRoyalty(address recipient, string memory tokenURI, address royaltyReceiver, uint96 roayltyFee)

public onlyOwner

returns (uint256) {

uint256 tokenId = mint(recipient, tokenURI);

_setTokenRoyalty(tokenId, royaltyReceiver, roayltyFee);

return tokenId;

}

function supportsInterface(bytes4 interfaceId) public view virtual override(ERC721, ERC2981)

returns (bool) {

return super.supportsInterface(interfaceId);

}

}

The above contract is a Solidity smart contract that implements a non-fungible token (NFT) using the ERC721 standard with the additional functionality of ERC2981, which is a standard for royalty payments on NFTs.

The _setDefaultRoyalty function is then called, which sets the default royalty receiver and charge for the NFT contract. The constructor first establishes the name and symbol of the NFT using the ERC721 constructor.

The contract defines four functions:

_burn: This is an internal function that overrides the _burn function in ERC721URIStorage to add the functionality of resetting the royalty for the token being burned.

burnNFT: This function allows the contract owner to burn (delete) an NFT from the contract.

mintNFT: This function allows the contract owner to mint (create) a new NFT and assign it to a specified recipient address. It uses the _safeMint function provided by ERC721URIStorage to create a new token ID and assign it to the recipient and then set the URI for the token.

mintWithRoyalty: This function allows the contract owner to mint a new NFT with royalty functionality. It calls the mintNFT function to create the token and then sets the royalty receiver and fee for the token using the _setTokenRoyalty function provided by ERC2981.

You might be interested in | Types of NFTs (Non-Fungible Tokens) You Didn’t Know

In addition, the contract modifies the ERC2981 and ERC721URIStorage supportsInterface functions to return true if the supplied interface is supported by the contract and false otherwise.

If you already have a project in mind and want to know how to get started with it, you may connect with our smart contract developer.

In case you have found a mistake in the text, please send a message to the author by selecting the mistake and pressing Ctrl-Enter.
Oodles Blockchain 68
Full-Stack Blockchain Development Services and Solutions for Startups and Enterprises for Business Excellence Transform your business processes into highly sec...
Comments (0)

    No comments yet

You must be logged in to comment.

Sign In / Sign Up