How to Create NFT Staking with Reward Features : Deploy CRC721 & NFT Staking – Coinex Smart Chain


NFT stands for Non Fungiable Token, NFT is a cryptographically unique type of token-crc721 and each nft token is associated with digital (and sometimes physical) content, nft can be used to provide proof of ownership of a digital work or property. NFT has many uses, including artwork, digital collectibles, music, and items in video games.

NFT is one of the sectors that has now experienced the fastest growth in the crypto industry. Non-exchangeable tokens are digital assets that contain identifying information that is recorded in a blockchain smart contract.

The meta data contained in each nft makes each nft token unique, and as such, they cannot be directly replaced by another token. Unlike crc20 tokens, nft tokens cannot be exchanged between each other, because each nft token is completely unique and one-of-a-kind.

NFT Staking is a dapps that has the function of staking crc-721 tokens into smart contracts, which aims to get token rewards (usually crc20 tokens). nft staking will make users more interested in collecting more nft, because of the reward staking feature that benefits users, this is a good strategy for developing projects.

In this article we will provide education on how to create nft staking with the reward feature (crc20 token), we will use the coinex smart chain blockchain to host the nft staking dapps. Why choose coinex smart chain? because the CSC blockchain (coinex smart chain) has high performance, very fast transaction processing (2-3 seconds), environmentally friendly (Dpos) and very cheap transaction fees.

 

What is needed ? 
1# Metamask Wallet

Metamask is a popular evm wallet, because it is very easy to use, it also supports many blockchains such as ethereum, binance smart chain, near, polygon matic, coinex smart chain, etc. I recommend that you use the metamask browser. After installing metamask, you need to set the rpc network to rpc coinex smart chain.

RPC URL : https://rpc.coinex.net
Network Name : Coinex Smart Chain
ChainID : 52
Symbol : CET
Block Explorer : https://www.coinex.net

 

2# Coin CET (Coin Native Coinex Smart Chain)

Coin CET is the native coin of the coinex smart chain blockchain, coin cet is used to pay for all transactions on the coinex smart chain network. We need a few coins to create smart contracts and interact contracts nft staking. You can buy coin cet on Coinex Exchange, after having coin cet, immediately send it to your metamask wallet address.

 

3# Smart Contract CRC20

We will use the crc20 token as a reward for stakeholders who stake nft in smart contracts. To create a crc20 token you need a solidity code, you can use the code below.

 // SPDX-License-Identifier: MIT
pragma solidity ^0.8.4;

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

contract TokenReward1 is ERC20 {
    constructor() ERC20("Token Reward 1", "TR1") {
        _mint(msg.sender, 1000000000 * 10 ** decimals());
    }
}

 

4# Smart Contract CRC721

Below is the solidity code to create a crc-721 token, you can use this code or use code from other sources.

 // SPDX-License-Identifier: MIT
pragma solidity 0.8.6;

import "https://github.com/0xcert/ethereum-erc721/blob/master/src/contracts/tokens/nf-token-metadata.sol";
import "https://github.com/0xcert/ethereum-erc721/blob/master/src/contracts/ownership/ownable.sol";

contract CVR1 is NFTokenMetadata, Ownable {

constructor() {
nftName = "CryptoVIR NFT 1";
nftSymbol = "CVR1";
}

function mint(address _to, uint256 _tokenId, string calldata _uri) external onlyOwner {
super._mint(_to, _tokenId);
super._setTokenUri(_tokenId, _uri);
}

}

 

5# Digital Works (Image/Animation/Digital Art)

You need digital works such as paintings, digital art, photos or any image for nft crc721 tokens. The image/photo will be uploaded to decentralized storage with the aim that the file is eternal (can be accessed forever) without an expiration date.

 

6# Decentralized Storage (IPFS/Siacoin)

To create nft or crc-721 tokens we need metadata, metadata is a json file containing information and unique nft id for each nft token. Metadata must be uploaded on a perpetual hosting (without expiration), for example, ipfs , siacoin and bittorent.

The Interplanetary File System (IPFS) is one of the popular distributed file storage protocols, ipfs allows computers around the world to store and serve files as part of a giant peer-to-peer network. Anyone can download the ipfs software and start uploading files and serving files on the ipfs network. When someone runs node ipfs , then they can upload files to the IPFS network, and those files can be viewed and downloaded by anyone in the world who is also running node ipfs.

Siacoin/Sia Network is one of the most popular blockchain-based cloud storage network, sia network uses decentralized storage by using underutilized hard drive storage space, Sia Storage Platform has created a new market for blockchain-based data storage. This provides a higher level of reliability in the cloud storage market and is a centralized storage solution and alternative. In addition, sia network has much lower rental costs and is more reliable than centralized cloud storage platforms.

 

7# Smart Contract NFT Staking
 // SPDX-License-Identifier: MIT
pragma solidity ^0.8.4;

import "@openzeppelin/contracts/token/ERC20/IERC20.sol";
import "@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol";
import "@openzeppelin/contracts/token/ERC721/IERC721.sol";
import "@openzeppelin/contracts/security/ReentrancyGuard.sol";

contract ERC721Staking is ReentrancyGuard {
    using SafeERC20 for IERC20;
    IERC20 public immutable rewardsToken;
    IERC721 public immutable nftCollection;

    constructor(IERC721 _nftCollection, IERC20 _rewardsToken) {
        nftCollection = _nftCollection;
        rewardsToken = _rewardsToken;
    }

    struct StakedToken {
        address staker;
        uint256 tokenId;
    }

    struct Staker {
        uint256 amountStaked;
        StakedToken[] stakedTokens;
        uint256 timeOfLastUpdate;
        uint256 unclaimedRewards;
    }
    uint256 private rewardsPerHour = 1000000000000000000000;
    mapping(address => Staker) public stakers;
    mapping(uint256 => address) public stakerAddress;
    function stake(uint256 _tokenId) external nonReentrant {
        if (stakers[msg.sender].amountStaked > 0) {
            uint256 rewards = calculateRewards(msg.sender);
            stakers[msg.sender].unclaimedRewards += rewards;
        }

        require(
            nftCollection.ownerOf(_tokenId) == msg.sender,
            "You don't own this token!"
        );


        nftCollection.transferFrom(msg.sender, address(this), _tokenId);
        StakedToken memory stakedToken = StakedToken(msg.sender, _tokenId);
        stakers[msg.sender].stakedTokens.push(stakedToken);
        stakers[msg.sender].amountStaked++;
        stakerAddress[_tokenId] = msg.sender; 
        stakers[msg.sender].timeOfLastUpdate = block.timestamp;
    }
    
    function withdraw(uint256 _tokenId) external nonReentrant {
        // Make sure the user has at least one token staked before withdrawing
        require(
            stakers[msg.sender].amountStaked > 0,
            "You have no tokens staked"
        );
        require(stakerAddress[_tokenId] == msg.sender, "You don't own this token!");
        uint256 rewards = calculateRewards(msg.sender);
        stakers[msg.sender].unclaimedRewards += rewards;

        uint256 index = 0;
        for (uint256 i = 0; i < stakers[msg.sender].stakedTokens.length; i++) { if ( stakers[msg.sender].stakedTokens[i].tokenId == _tokenId && stakers[msg.sender].stakedTokens[i].staker != address(0) ) { index = i; break; } } stakers[msg.sender].stakedTokens[index].staker = address(0); stakers[msg.sender].amountStaked--; stakerAddress[_tokenId] = address(0); nftCollection.transferFrom(address(this), msg.sender, _tokenId); stakers[msg.sender].timeOfLastUpdate = block.timestamp; } function claimRewards() external { uint256 rewards = calculateRewards(msg.sender) + stakers[msg.sender].unclaimedRewards; require(rewards > 0, "You have no rewards to claim");
        stakers[msg.sender].timeOfLastUpdate = block.timestamp;
        stakers[msg.sender].unclaimedRewards = 0;
        rewardsToken.safeTransfer(msg.sender, rewards);
    }


    function availableRewards(address _staker) public view returns (uint256) {
        uint256 rewards = calculateRewards(_staker) +
            stakers[_staker].unclaimedRewards;
        return rewards;
    }

    function getStakedTokens(address _user) public view returns (StakedToken[] memory) {
        // Check if we know this user
        if (stakers[_user].amountStaked > 0) {
            // Return all the tokens in the stakedToken Array for this user that are not -1
            StakedToken[] memory _stakedTokens = new StakedToken[](stakers[_user].amountStaked);
            uint256 _index = 0;

            for (uint256 j = 0; j < stakers[_user].stakedTokens.length; j++) {
                if (stakers[_user].stakedTokens[j].staker != (address(0))) {
                    _stakedTokens[_index] = stakers[_user].stakedTokens[j];
                    _index++;
                }
            }

            return _stakedTokens;
        }
        
        // Otherwise, return empty array
        else {
            return new StakedToken[](0);
        }
    }
 
    function calculateRewards(address _staker)
        internal
        view
        returns (uint256 _rewards)
    {
        return (((
            ((block.timestamp - stakers[_staker].timeOfLastUpdate) *
                stakers[_staker].amountStaked)
        ) * rewardsPerHour) / 3600);
    }
}

 

How to Make NFT Staking with Reward Features
1# Deploy Token CRC-20

The CRC20 token will later be used as a reward for stakeholders who stake the crc-721 (nft) token in the smart contract. To create a crc20 token you need a little coin cet for the deploy process

  • Go to the remixIDE website and create a new file there
  • Paste the solidity code into the file, and don’t forget to edit the “contract name“, “symbol token“, “name” and “total supply” for the token

  • Compile code smart contract: Go to the “Solidity Compiler” menu, select the compiler version, “Enable Optimization – 200” . Make sure the green status appears, which means the compilation is complete and there are no errors

  • Deploy smart contract: Enter the “Deploy & Run Transaction” menu, Click “Environment” and select the wallet you will use
  • Click Deploy

 

2# Deploy Token CRC-721
  • Open remixIDE and create a new file there
  • Paste the solidity code for crc-721
  • Edit in the “contract” section, “token name” “token symbol
  • Compile the file with the appropriate compiler
  • Deploy smart contract

 

3# Deploy NFT Staking
  • Open remixIDE and create a new file there
  • Paste the solidity code for NFT-Staking
  • Edit in the contract section:  contract ERC721Staking
  • Edit reward amount for staker : uint256 private rewardsPerHour = 1000000000000000000000;

  • Because the token uses decimal 18, you need to add 18 (0)
  • Compile the file with the appropriate compiler
  • Enter the CRC721 smart contract in the field “_NFTCOLLECTION:”
  • Enter the CRC20 smart contract in the field  “_REWARDSTOKEN:”

  • Deploy smart contract

Continue to Next Article / Part 2


Alif Fahmi

hi , I'm Alif, I'm a blockchain & cryptocurrency lover, I love writing & learning, my job is web developer & crypto trader