Welcome back to the second part of the article on Fractional NFTs. This part explores the technical details involved in creating a Fractional NFT smart contract. To kick off, make sure you’ve studied the first part of the article which will provide you with a foundational understanding of Fractional NFTs, and their importance in the digital asset space.
Whether you're an experienced developer or a curious enthusiast, this guide aims to provide a clear, step-by-step process for fractionalizing an NFT, offering insights into the future of decentralized asset ownership. This process will guide you through the requirements to make a single NFT divisible into multiple fungible parts.
Prerequisites
Before you proceed with this tutorial, the following are required:
Basic understanding of Blockchain Technology.
Knowledge of Solidity.
Understanding of smart contract development.
Have Metamask installed and test tokens.
Basic knowledge of how to use Remix IDE.
To recap, fractional NFTs are achieved by using fungible tokens (ERC-20) to create fractions of an NFT (ERC-721). In the following steps, we will learn how to fractionalize an NFT. So without further ado, let’s dive in.
Tutorial: Creating a Fractional NFT Smart Contract
Create an ERC-20 token smart contract
The first step to fractionalizing an NFT is to create an ERC-20 smart contract with additional functionalities. This smart contract will be responsible for fractionalizing an NFT.
Open up Remix IDE using this link.
On the File Explorer tab, create a new folder named FractionalNFT inside the contracts folder.
Inside the newly created folder, create a file, and name it FractionalNFT.sol.
Copy the code snippet and paste it inside the FractionalNFT.sol file you just created.
// SPDX-License-Identifier: MIT pragma solidity ^0.8.4; import "@openzeppelin/contracts/token/ERC20/ERC20.sol"; import "@openzeppelin/contracts/token/ERC721/IERC721.sol"; import "@openzeppelin/contracts/access/Ownable.sol"; import "@openzeppelin/contracts/token/ERC20/extensions/draft-ERC20Permit.sol"; import "@openzeppelin/contracts/token/ERC721/utils/ERC721Holder.sol"; contract FractionalNft is ERC20, Ownable, ERC20Permit, ERC721Holder { IERC721 public collection; uint16 public tokenId; bool public initialized; bool public forSale; bool public redeemable; uint256 public salePrice; constructor() ERC20("Token Fraction", "TKF") ERC20Permit("Token Fraction") Ownable(msg.sender) {} function initialize(address _collection, uint16 _tokenId, uint256 _amount) external onlyOwner { require(!initialized, "Already initialized"); require(_amount > 0, "can't initialize zero amount"); collection = IERC721(_collection); collection.safeTransferFrom(msg.sender, address(this), _tokenId); tokenId = _tokenId; initialized = true; _mint(msg.sender, _amount); } function putForSale(uint256 price) external onlyOwner { salePrice = price; forSale = true; } function purchase() external payable { require(forSale, "Not for sale"); require(msg.value >= salePrice, "Not enough ether to purchase"); collection.transferFrom(address(this), msg.sender, tokenId); forSale = false; redeemable = true; } function redeem(uint256 _amount) external { require(redeemable, "Redemption not available"); uint256 totalEther = address(this).balance; uint256 amountToRedeem = _amount * totalEther / totalSupply(); _burn(msg.sender, _amount); (bool sent, ) = payable(msg.sender).call{value: amountToRedeem}(""); require(sent, "Failed to send Ether"); } }
Explaining the Important Functions
initialize()
The initialize function is the main function that performs the action of fractionalizing an NFT. It carries out the process by transferring an NFT from the owner to the FractionalNFT smart contract, and then mints an amount of ERC-20 tokens to the NFT owner, which represents the fractions of the NFT that was transferred into the smart contract.
putForSale()
This function enables sale of the NFT. The value of the forSale variable is false by default, which means the NFT is not for sale, when the putForSale function is called, it takes the price the NFT is to be sold for and then sets the forSale variable to true.
purchase()
This function, which is payable, is used to purchase the NFT from the FractionalNFT smart contract. The user initiating this function needs to specify the price of the NFT in ETH during the function call. Importantly, this function can only be executed when the forSale feature is enabled. Upon a successful purchase, the NFT is transferred from the smart contract to the address of the user who made the purchase.
redeem()
The redeem function can only be called when the redeemable variable is set to true, indicating that users who own a fraction of the ERC-20 token that makes up the NFT can redeem the ETH value the NFT was sold for, from the smart contract. When a user calls the redeem function, the contract uses the fraction of token the user has from the total supply, and calculates the amount of ETH to send to the user, then it sends the ETH value to the user’s address.
Now that we have explained the main functions, let’s continue with the tutorial.
After pasting the code snippet inside the FractionalNFT.sol file, click on the Solidity Compiler tab, and click the blue compile button to compile your smart contract. Make sure there is a green tick on the Solidity compiler tab that indicates that your smart contract has compiled successfully.
We have now completed the smart contract for fractionalizing NFT, let’s create the NFT smart contract.
Create the NFT (ERC-721) smart contract
After creating an ERC-20 token smart contract which will handle fractioning an NFT, we will also need to create the NFT contract itself.
In the same FractionalNFT folder, create a file named HooziNFT.sol. You can use any preferred name of your choice.
Copy the code beside and paste it inside the HooziNFT.sol file you created.
// SPDX-License-Identifier: MIT pragma solidity ^0.8.4; import "@openzeppelin/contracts/token/ERC721/ERC721.sol"; import "@openzeppelin/contracts/access/Ownable.sol"; contract HooziNFT is ERC721, Ownable { constructor() ERC721("HooziNFT", "HOZ") Ownable(msg.sender) {} function safeMint(address to, uint256 tokenId) public onlyOwner { _safeMint(to, tokenId); } }
Click on the Solidity compiler tab, and compile the HooziNFT contract.
You should see a green tick on the Solidity compiler tab.
Deploy FractionalNFT contract
Click on the Deploy & run transactions tab on Remix.
Select the FractionalNFT contract.
Click on the orange Deploy button.
After deployment, you should see the deployed smart contract in the Deployed Contracts section on Remix like so:
Deploy the HooziNFT contract
Now let’s deploy the actual NFT smart contract we will be fractionalizing.
Click on the Deploy & Run Transactions tab on Remix.
Select the HooziNFT contract, and hit the orange Deploy button.
After deployment, you should see the deployed HooziNFT smart contract in the Deployed Contracts section on Remix like so:
Interaction with the Deployed HooziNFT contract
We need to interact with the deployed NFT smart contract to mint an NFT, and approve the FractionalNFT (ERC-20) smart contract to spend the NFT.
Copy the wallet address provided by Remix VM.
Click on the deployed HooziNFT contract.
Interact with the safeMint function by clicking the button after filling the required input fields. Use the wallet address you copied as the value for the to input field, and the tokenId value should be 1.
Click on the transact button to mint an NFT to the address you passed as the to value.
After clicking the transact button, the transaction should run successfully, showing a green tick in the Remix transaction log.
Now, let’s approve the FractionalNFT contract, given it the permission to transfer all the NFTs owned by the function caller.
Use the setApprovalForAll function, pass in the address of the FractionalNFT contract, and set the approved value to true.
Click the transact button to run the transaction.
Now we have completed the interaction with the deployed HooziNFT contract, let’s now move over to the FractionalNFT (ERC-20) contract.
Interaction with the Deployed FractionalNFT (ERC-20) contract
The FractionalNFT contract is an ERC-20 contract that is responsible for fractionalizing an NFT, let’s now interact with it.
Click on the deployed FractionalNFT contract.
Interact with the initialize function by filling the required input fields.
The value of the _collection, should be the contract address of the deployed HooziNFT contract.
The value of the _tokenId should be 1, which is the id of the token that was minted to the address that will be calling the initialize function.
The value of _amount is the number of fractions you want the NFT to be splitted into. In our case, we will be using 1000 and an extra 18 zeros as decimals (1000000000000000000000 or 1000e18), which means the NFT we want to fractionalize will be splitted into 1000 fractions.
Once the input values are correctly filled, click the transact button.
Your transaction should run successfully with a green check in the transaction log.
To confirm if the transaction was successful, click on the blue collection button, it should display the contract address of the deployed HooziNFT.
Check the balanceOf the FractionalNFT ERC-20 token of the address that called the initialize function, you will notice that 1000 tokens have been minted to the address. Those tokens can be sent to another address to own a fraction of the NFT with token ID of 1.
Transfer a fraction of the FractionalNFT ERC-20 token to another address
Copy the address of the second account in the list of accounts provided by Remix:
After copying the address, switch back to the previous account you were using and interact with the transfer function of the deployed FractionalNFT contract.
The value of the to input field should be the address of the second account you copied.
Value field should be the amount of fraction you want the address to own, we will be using 100 plus 18 zeros for decimals (100000000000000000000 or 100e18).
Put the NFT for sale
Call the putForSale function of the deployed FractionalNFT contract, passing the amount you wish to sell the NFT, we will be setting the amount to be 10 ETH, 10 and 18 zeros for decimal (10000000000000000000 or 10e18).
Use another address to purchase the NFT
Now that the NFT is available for sale, switch your Remix VM account to the third account on the list and use it to buy the NFT in the FractionalNFT contract.
This is the third account on the Remix VM list of accounts, see that 10 ETH is set to interact with the purchase function.
Click the red purchase button to purchase the NFT.
After the NFT purchase, notice that the ETH balance of the third account has reduced by 10 ETH.
Redeem ETH using the FractionalNFT ERC-20 account balance
Now that the NFT has been purchased, the 10 ETH that was paid for the NFT is in the FractionalNFT contract. Only accounts that hold the FractionalNFT ERC-20 tokens can redeem the ETH in the contract based on the amount (fraction) of tokens they hold. In this tutorial, only the first and second accounts in the Remix VM hold FractionalNFT ERC-20 tokens. Let’s use them to redeem the ETH in the contract.
Switch account to the second account in the Remix VM.
Check the ETH balance of the account so that you can track if the balance increased after redeeming the ETH in the FractionalNFT smart contract.
Check the balance of FractionalNFT ERC-20 token owned by this account.
Copy the token balance and paste it in the input field beside the redeem button.
Click on the redeem button to redeem your ETH.
Now check the ETH balance of your account if it increased after redeeming ETH with the fraction of token in the third account.
Notice that the ETH balance has increased. It was 100 ETH earlier.
Let’s now redeem with the first account which has more fractions of the FractionalNFT ERC-20 token.
Switch to the first account in the Remix VM accounts.
Check the ETH balance of the account before redeeming.
Check the FractionalNFT ERC-20 balance of the account.
Copy the balance and paste it in the input field beside the redeem button.
Click the redeem button and then check the ETH balance of the account again.
Notice that the ETH balance of the account has increased, this account holds most of the FractionalNFT ERC-20 tokens and it got almost all the ETH that was paid for the NFT.
If the ERC-20 token, once minted, is distributed to various wallet addresses, each of these addresses becomes an automatic owner of a portion of the specified NFT (whose ID was set in the FractionalNFT contract). These owners can then redeem a proportionate amount of the NFT's sale value using the quantity of ERC-20 tokens they possess, reflecting the fraction they hold.
And with that, we've successfully completed the implementation of Fractional NFTs using an ERC-20 token and an ERC-721 token.
Conclusion
This guide has walked us through the details of breaking down an NFT into fractions, blending the features of ERC-20 and ERC-721 tokens to mold a unique digital asset ownership experience. Beyond just boosting NFT liquidity, this approach sets the stage for more inclusive and accessible ways of owning assets in the digital world. As the blockchain scene progresses, Fractional NFTs stand out as a symbol of innovation, opening up fresh opportunities for creators, collectors, and developers.