Build an NFT Staking Smart Contract with Solidity & Thirdweb Deploy! (2023)

In this guide we create:

  1. An ERC-721NFT Drop Smart Contractwithcoined lazilyNFTs users can emboss
  2. Your ownERC-20Token smart contract
  3. OnNFT Staking Smart Contractwhere users can wager their NFTs and earn tokens for doing so!

In the end we will have a full stack web application where users can see what NFTs they own, put them on the smart contract and claim their rewards!

Let us do this!

what we build

You can check out a demo of the finished product below:

nft-staking-contract.thirdweb-example.com

Source code

The full source code can be accessed here:

Let's begin!

Our goal with the NFT Drop is to upload all of our NFT metadata and then allow users to come to our site and mint a random NFT from our collection.

We can do this withThirdweb's pre-built NFT drop contract!

Thirdweb's drop contracts lazily create your NFTs and make them available for your users to claim.

That's exactly what we need! Alright, let's go ahead and create our NFT Drop!

Creating the NFT drop contract

Go toThirdweb-Dashboardand connect your wallet.

Then clickProvide new contract.Build an NFT Staking Smart Contract with Solidity & Thirdweb Deploy! (1)

What we want is theNFT-Dropcontract, let's clickDeploy nowon this one!

Build an NFT Staking Smart Contract with Solidity & Thirdweb Deploy! (2)

You can configure theName,Symbol,description,Bild, androyaltyInformation in settings before deploying your NFT Drop.

I call my NFT Dropcolored shapesand stick with the default values ​​for the rest of the fields, but feel free to go wild and configure this to your liking!

Build an NFT Staking Smart Contract with Solidity & Thirdweb Deploy! (3)

Once satisfied, let's deploy this NFT drop on theMumbai (MATIC) Testnetz.

Build an NFT Staking Smart Contract with Solidity & Thirdweb Deploy! (4)

This will prompt you to accept a transaction in MetaMask (or any wallet you've connected to) and deploy your smart contract on the Mumbai Test network!

Build an NFT Staking Smart Contract with Solidity & Thirdweb Deploy! (5)

You may find that the MetaMask transaction requests usDeploy Proxy. What on earth does that mean? Let's briefly explore what happens when we deploy a pre-built contract to Thirdweb.

Ready-made contracts and provision of a proxy

Thirdweb v2 introducedProxy Contracts. See the documentation at for a full breakdownHow Thirdweb pre-packaged contracts work.

In short, most of the smart contract logic was built and deployed by Thirdweb; They are providing one right nowproxy contract, which stores specific informationYOURsmart contract. B. Name, Description, Icon, Owner and Royalty Configuration.

Since all NFT contracts hosted on Thirdweb have the same logic for things like minting and burning NFTs, we can justdelegatethese function calls to the Thirdweb Base Contracts; where the "real" logic lives.

That way it's round10 times cheaperto deploy our smart contracts as we deploy a lot less code and let the Thirdweb base contracts do all the logic for us.

Here's a simple diagram to explain how this works:

Build an NFT Staking Smart Contract with Solidity & Thirdweb Deploy! (6)

Okay, now that we know what we're providing, let'sTo confirmthis transaction and proceed!

Define entitlement phases

claim phasesare conditions we can configure that define when and how users can claim NFTs from our collection.

A popular claim phase pattern is to have a claim phase where allowlisted wallets can claim and then another phase where they can claimanywallet can claim.

Let's click in the Thirdweb dashboardSet entitlement phaseand configure a simple claim stage where anyone can mint/claim our NFTs.

(Video) Build an NFT Staking Smart Contract + Web Application πŸš€ Solidity, thirdweb deploy, Next.JS Tutorial

Build an NFT Staking Smart Contract with Solidity & Thirdweb Deploy! (7)

Click onadd stage, and configure it to your liking!

I'll change thoseHow many NFTs can be claimed per transaction?to be1, and accept the default values ​​for the other fields.

If you are satisfied with your application phase(s), clickUpdate claim stages

Build an NFT Staking Smart Contract with Solidity & Thirdweb Deploy! (8)

Lazy Minting NFTs

Great, now we've set up a claim phase, users can start claiming NFTs from our collection! So let's create these NFTs now.

ThirdwebsFallencontractsRotten Mintyour NFTs. That means the user whoExpectationsthe NFT is the one that actually shapes the NFT they claim.

If you add NFTs to your Drop contract, they will not be minted at this time. You prepare everything for your users to mint the NFT(s). This means that the user claiming the NFT is the one who mints it and it gets minted in their wallet. By default, the user is the one who pays the gas fees.

So now all we have to do is upload the metadata for our NFTs, such as: B. the images, names and descriptions of each NFT.

How to batch upload NFT metadata

If you don't already have any NFTs that you want to upload, you can use Thirdweb's sample files to create a dummy NFT collection. You can access both from the following links:

Build an NFT Staking Smart Contract with Solidity & Thirdweb Deploy! (9)

Upload your metadata file to the drag-and-drop area along with your images, and voila!

Build an NFT Staking Smart Contract with Solidity & Thirdweb Deploy! (10)

Your NFTs are ready for you to upload:

Build an NFT Staking Smart Contract with Solidity & Thirdweb Deploy! (11)

Make sure you're happy with how it looks, then scroll down and clickNext!

You then have the option to add oneDelayed Reveal, that's up to you! For the purpose of this guide, I will choosePoint to mint.

Build an NFT Staking Smart Contract with Solidity & Thirdweb Deploy! (12)

Then I strikeUpload 30 NFTs!

We're again prompted to approve a transaction, this time the name is a little more obvious - we areRotten embossingthe NFTs we just uploaded so I'm clickingTo confirm.

Build an NFT Staking Smart Contract with Solidity & Thirdweb Deploy! (13)

Once the transaction is confirmed we can see all of our NFTs that we just uploadedoverviewNFT Drop tab.

Build an NFT Staking Smart Contract with Solidity & Thirdweb Deploy! (14)

Brilliant! Now our users are ready to mint the NFTs from our collection.

Before we set that up, let's create our ownERC-20-Tokenalso.

Creating our token is even easier than creating our NFT drop, we follow the same path of clickingProvide new contractandDeploy now, except this time we use aSignContract instead of an NFT drop.

I configure my token with these settings and clickDeploy now, re-deploying on theMumbai (MATIC)test network.

Build an NFT Staking Smart Contract with Solidity & Thirdweb Deploy! (15)

Once we've created our token, let's mint the initial endowment so we can later reward users for staking their NFTs. We can easily do that on the dashboard by clickingmintKnopf.

Build an NFT Staking Smart Contract with Solidity & Thirdweb Deploy! (16)

For the sake of simplicity, I first create 100 of these tokens per clickcoin tokens, and approve themint tooTransaction in MetaMask.

Build an NFT Staking Smart Contract with Solidity & Thirdweb Deploy! (17)

Big! Now we have 100 tokens! In the next step we will be able to transfer these to our staking smart contract so that they can be sent as rewards through the contract.

Build an NFT Staking Smart Contract with Solidity & Thirdweb Deploy! (18)

Now let's create our staking smart contract!

(Video) NFT Staking Smart Contract Tutorial

The purpose of our staking contract is to store users' NFTs from our NFT drop contract and reward them with tokens from our token contract.

The longer the user's NFT stake, the more tokens they will be rewarded.

To be fair where it's due, most of this code for this staking contract comes from this repo:

But we will go through step by step how to build and understand the features of this contract, and addProvide third webto the contract so that we:

  • Configure and implement it from the Thirdweb dashboard
  • Generate TypeScript functions to interact with our contract
  • Use the Thirdweb React and TypeScript SDKs to easily consume the contract and blockchain.

Build the project

For this guide I useNext.js&Typescriptto set up the project and we create the smart contract directly in the project for the sake of simplicity.

Feel free to use the tools you are familiar with or follow the steps in this guide to end up with the same result!

Initialize the Next.JS project with Thirdweb

To create a new project using Next.JS, TypeScript and Thirdweb, we can use Thirdwebscreate-thirdweb-dappCLI-Tool:

npx create-thirdweb-dapp --next --ts

Change to the newly cloned repo directory:

CD.\nft-staking-app\

Now we have a simple example of Next.JS + Thirdweb + Typescript setup where we can use Thirdweb's helpful hooks to connect, disconnect and display our MetaMask wallet on the homepage.

Writing the staking contract

We're going to use some of the [OpenZeppelin Contracts] within our contract, so we need to install those@openzeppelin/contractsPackage in our project:

npm install @openzeppelin/contracts

First, let's create a new file in the root of our project calledStakingContract.sol, which is a Solidity file.

If you're new to Solidity, I'd recommend installing an extension that offers syntax highlighting, as it's called heresolidityto make it much easier to read.

Let's define our license, imports and contracts in this file:

// SPDX license identifier: MITPragma 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 {}

Now let's go through how thatstaking contractis structured and write it down step by step!

First, let's create some variables in which we will store the contract address of theNFT collectionandSignthat we created earlier:

// We do this so we can use the safeTransfer functionuse SafeERC20 Pro IERC20;// Interfaces for ERC20 and ERC721IERC20Publicity immutableReward token; IERC721Publicity immutablenftCollection;

We can use aStructureto store information about a staked token:

 Structure StakedToken{addressCalls;uint256tokenId; }

Now let's do oneStructurecalledCalls, which presents the information we need about a wallet putting its NFTs on our contract:

 // Information about the deployment Structure Calls{// Amount of tokens staked by the staker uint256AmountStaked;// Gestackte Token-IDsStakedToken[] StakedTokens;// Lastly, the bonuses were calculated for this user uint256timeOfLastUpdate;// Calculated but unclaimed rewards for the user. The rewards are // will be calculated every time the user writes to the smart contract uint256unclaimed rewards; }

Next we configure how many tokens we want to reward perHourthe NFT was staked:

 // Rewards per hour per deposited token in Wei. uint256 Privaterewards per hour= 100000;

Somemappings store knowledge about:

  • Wallet-Adresse anCalls(so we know which wallet is which staker)
  • Token ID to wallet address (so we know which NFT is being staked by which wallet)
 // Mapping the user address to the staker info mapping(address =>Calls)PublicityStriking;// Mapping the token ID to the staker. Made for the SC to remember // Who to send the ERC721 token back to. mapping(uint256 => address)PublicitystakerAddress;

Theconstructor, which allows us to set the value of the NFT capture contract address and the token contract address when we deploy the contract (we will do this on the Thirdweb dashboard);

 // Constructor function to set the reward token and NFT collection addresses constructor(IERC721 _nftCollection, IERC20 _rewardsToken){ nftCollection=_nftCollection; RewardToken=_rewardsToken; }

Now for the features!

First up is a feature that allows the usermissionihre NFT.

This function must also store the knowledge of which wallet address has which token IDs in the walletmappings we created:

 // If the address has already staked ERC721 token/s, calculate the rewards. // Increase the staked amount and map msg.sender to the stake's token id // Token to send back later on payout. Finally, give timeOfLastUpdate the // value from now. function mission(uint256_tokenId)extern not reentrant {// If the wallet has tokens staked, calculate the rewards before adding the new token if(Striker[news.Sender].AmountStaked> 0) {uint256Reward=calculaterewards(news.Sender); strikernews.Sender].unclaimedRewards+=Reward; }// Wallet must own the token you are trying to stake require(nftCollection.ownerOf(_tokenId)== news.Sender,"You don't own this token!");// Transfer the token from the wallet to the smart contractnftCollection.transferFrom(news.Sender,address(this), _tokenId);// Reset stakedTokenStakedTokenMemoryStakeToken=StakedToken(news.Sender, _tokenId);// Add the token to the stakedTokens arraystrikernews.Sender].stakedTokens.to press(stakedToken);// Increase the bet amount for this walletstrikernews.Sender].AmountStaked++;// Update the mapping of the TokenId to the staker's addressstakerAddress[_tokenId]= news.Sender;// Update timeOfLastUpdate for the stakerstrikernews.Sender].timeOfLastUpdate= Block.time stamp; }

A feature that allows the userwithdrawthe NFTs they staked:

 // Check if the user has wagered ERC721 tokens and if he tried to withdraw, // Calculate the rewards and store them in the unclaimedRewards // Decrement the user's amount and return him the ERC721 token function withdraw(uint256_tokenId)extern not reentrant {// Make sure the user has wagered at least one token before withdrawing require(Striker[news.Sender].AmountStaked> 0,"You have not placed any tokens");// Wallet must hold the token they are trying to withdraw require(StrakerAddress[_tokenId]== news.Sender,"You don't own this token!");// Update the rewards for this user as the number of rewards decreases with fewer tokens. uint256Reward=calculaterewards(news.Sender); strikernews.Sender].unclaimedRewards+=Reward;// Find the index of this token id in the stakedTokens array uint256Index= 0;Pro(uint256I= 0; I<strikernews.Sender].stakedTokens.Long; I++) {if(Striker[news.Sender].stakedTokens[i].tokenId==_tokenId&&strikernews.Sender].stakedTokens[i].stakedTokens!= address(0) ) { Index=I;interruption; } }// Set this token's .staker file to address 0 to mark it as unstakedstrikernews.Sender].stakedTokens[index].stakes= address(0);// Decrease the bet amount for this walletstrikernews.Sender].AmountStaked--;// Update the mapping of the tokenId to the be address (0) to indicate that the token is unstakedstakerAddress[_tokenId]= address(0);// Transfer the token back to the withdrawernftCollection.transferFrom(address(this),news.Sender, _tokenId);// Update timeOfLastUpdate for the off hookstrikernews.Sender].timeOfLastUpdate= Block.time stamp; }

Finally we have a function for the useraccept rewardso they can be rewarded with the tokens we created for staking their NFT:

 // Calculate rewards for the msg.sender, check if there are any rewards // claim, set unclaimedRewards to 0 and transfer the ERC20 reward token // for the user. function accept reward()extern {uint256Reward=calculaterewards(news.Sender)+strikernews.Sender].unclaimedRewards;require(Reward> 0,"You have no rewards to claim"); strikernews.Sender].timeOfLastUpdate= Block.time stamp; strikernews.Sender].unclaimedRewards= 0; RewardsToken.safeTransfer(news.Sender, Reward); }

These are the core pieces of our contract, but you may have noticed that there is a feature we call namedCalculate bonuses.

This function calculates the time that has elapsed since the contract last checked thisCalls's calculated rewards.

This feature isintern, which means it's not open to the public, only other functions within that smart contract.

 // Calculate rewards for param _staker by calculating elapsed time // since last update in hours and multiply by ERC721 tokens staked // und RewardsPerHour. function Calculate bonuses(address_Calls)intern outlook returns(uint256_Reward){return((( ((Block.time stamp -Strikers[_staker].timeOfLastUpdate)*Player[_Player].AmountStaked) )*rewards per hour)/ 3600); }

Amazing work! That's the whole logic of our contract, now we just have to add somethingoutlooks so that we can retrieve this information.

We'll add a view to read the token IDs that a user currently has:

 function getStakedTokens(address_User)Publicity outlook returns(StakedToken[]Memory){// Check if we know this user if(stakers[_user].amountStaked> 0) {// Return all tokens in the stakedToken array for this user that are not -1StakedToken[]Memory_stakedTokens= NeuStakedToken[](stakers[_user].amountStaked);uint256_Index= 0;Pro(uint256j= 0; j<stakers[_user].stakedTokens.Long; j++) {if(stakers[_user].stakedTokens[j].staker!=(address(0))) { _stakedTokens[_index]=stakers[_user].stakedTokens[j]; _Index++; } }return_stakedTokens; }// Otherwise return an empty array anders{return NeuStakedToken[](0); } }

Another to read the available rewards a user has:

 function available awards(address_Calls)Publicity outlook returns(uint256){uint256Reward=computeRewards(_staker)+Stakers[_staker].unclaimedRewards;returnReward; }

That's it! Now we can upload our contract to the Thirdweb dashboard using Thirdweb Deploy.

Upload the contract with Thirdweb deploy

Now we can upload our contract to Thirdweb.

(Video) DApp Smart Contracts Staking, Unstaking, & Rewards - Complete DApp Course

Let's run the following from the command line:

npx Thirdweb deployment

The result you see should look like this:

πŸ’Ž Thirdweb-Cli v0.4.53πŸ’ŽWARNING Unable to recognize projectTyp, Fallback to Solc CompilationINFO Recognized Thirdweb Contracts:"ERC721Staking"INFO Project compiled successfullyINFO Uploading contract data...INFO Uploaded successfullyINFO Open this link to deploy your contracts: https://thirdweb.com/contracts/deploy?ipfs=<your-ipfs-url-here>

If everything was successful, you can open this URL in your browser, which will take you to a page where you can provide your contract. No private key is required!

Build an NFT Staking Smart Contract with Solidity &amp; Thirdweb Deploy! (19)

Let's clickDeploy nowand put our staking contract on theMumbai (MATIC)test network.

Here we have to fill in the required fields that we have defined in ourconstructor.

When you return to the dashboard, you can access the contract addresses of your NFT collection and your token contracts and insert them into the contract parameters here:

Build an NFT Staking Smart Contract with Solidity &amp; Thirdweb Deploy! (20)

You've just deployed your own custom smart contract in a few clicks!

Let's see how we can integrate it into our application now!

Our generated SDK

If you look at themCodeNow click on the Thirdweb dashboard and see a fully generated list of features that we can interact with just by using the Thirdweb SDK!

Build an NFT Staking Smart Contract with Solidity &amp; Thirdweb Deploy! (21)

You can see all the functions we wrote howmission,withdraw, andaccept reward.

The best part is that we don't need to use any other tools to interact with our smart contract, we can just use TypeScript! The Thirdweb SDKs do the rest.

Now let's build the front-end of this application for our users to claim and stake their NFTs and start earning rewards!

Creating the frontend application

In this guide, I use CSS modules to style the app. If you want to use the same styles as me, feel free to create a filestyles/Home.module.cssandstyles/globals.cssand use the files provided in itsample repository.

Remember to import these files if needed.

Let's go first_app.tsxand configure theactiveChainIdto be setChainId.Mumbai;, so:

artactiveChainId = ChainId.Mumbai;

Then visit our website atindex.tsx, and create a simple page that allows users to navigate to two different pages:

  1. That/MintRoute where they can use our NFT collection contract to mint one of our lazy minted NFTs from the collection.
  2. That/MissionRoute where they can see which NFTs they own from this collection, put their NFT on the contract and claim their rewards.

Here's the code for it, with the styling removed for simplicity:

import{useRouter}von "next/router";arthome =() =>{artrouter = useRouter();return(<div> <h1>Thirdweb Deploy - Custom staking contract</h1> <div onClick={()=>router.push(`/mint`)}><h2>Mint a new NFT</h2> <p>Use the NFT Drop contract to claim an NFT from the collection.</p> </div> <div onClick={()=>router.push(`/stake`)}><Bild Those={`/Symbol/token.webp`}alt="fallen"/> <h2>Deploy your NFTs</h2> <p>Use the custom staking contract provided via<b>Thirdweb Deployment</b>{" "} to stake your NFTs and earn tokens<b>Sign</b>Contract.</p> </div> </div>);};Export OriginallyAt home;

With some additional styles and images it looks like this:

Build an NFT Staking Smart Contract with Solidity &amp; Thirdweb Deploy! (22)

Now we need to create these pages. In yourpagesfolder, create two new files namedmint.tsxandstake.tsx, these will be separate routes where we can handle the logic for embossing and staking.

mint side

The Mint page shows the user a button to claim the next available NFT in our NFT drop. Since we lazily coined these NFTs, the user will be the one doing itmints the NFT and pay the gas fee for coining.

Now let's go through the parts of this claims page!

First, let's create a functional component and import the necessary parts of the SDK to make this work:

import{ useAddress, useMetamask, useNFTDrop }von "@thirdweb-dev/react";import{useRouter}von "next/router";artmint =() =>{artrouter = useRouter();return(<div> </div>);};Export OriginallyMint;

Let's then import the helpful hooks from the@thirdweb-dev/reactPackage:

 // Get the address of the currently connected wallet artAdresse = useAddress();// Function to connect to the user's metamask wallet artconnectWithMetamask = useMetamask();// Get the NFT capture contract artnftDropContract = useNFTDrop("<your-NFT-drop-contract-address-here");

Now we have our NFT drop contract saved in oursnftDropContractvariable, just by using a line of code! How cool is that!

We need a function that allows users to claim an NFT from our collection. This function displaysAlarmif the claim is successful or if something goes wrongcatchBlock. Once the user closes the successful notification, we navigate them to/MissionRoute so they can use their NFT if they want!

 asynchronous function ClaimNft(){To attempt{arttx =expectnftDropContract?.claim(1);console.log(tx); Alarm("NFT Claimed!"); router.push(`/insert`); }catch(Error) {console.error(error); warning (error); } }

Now for the UI! We need to make sure the user is connected to the website with their wallet before minting; Otherwise the function will not work as there is no connected wallet.

For this we use aternaries Operatora showconnect walletButton if there is no connected wallet (withaddress) or show aRequest an NFTbutton if availableisa connected wallet:

<> {!Address? (<Knopf onClick={connectWithMetamask}>connect wallet</Knopf>) : (<Knopf onClick={()=>ClaimNft()}> Claim an NFT</Knopf>)} </div>

Big! Now with some extra styling, we can both seeconnect walletOutlook:

Build an NFT Staking Smart Contract with Solidity &amp; Thirdweb Deploy! (23)

And theRequest an NFTOutlook:

Build an NFT Staking Smart Contract with Solidity &amp; Thirdweb Deploy! (24)

(Video) How to Build a Play to Earn Blockchain Game

when we clickconnect wallet, we are prompted to connect our MetaMask wallet to this website, can then claim an NFT and are redirected to/MissionRoute after approval ofclaimTransaction.

Build an NFT Staking Smart Contract with Solidity &amp; Thirdweb Deploy! (25)

Now we're on the/MissionRoute, let's code this part!

stake page

The Stakes page will have three sections:

  1. Information about theSign
  2. Gestakte NFTs
  3. Unstaked NFTs

First, let's import all the necessary functions for this page:

import{ ThirdwebNftMedia, useAddress, useMetamask, useNFTDrop, useToken, useTokenBalance, useOwnedNFTs, useContract,}von "@thirdweb-dev/react";import{ BigNumber, Ether }von "Ether";importType { next page }von "next";import{ useEffect, useState }von "react";importStilevon "../styles/Home.module.css";

And we create some variables for our contract addresses so that we can easily access them in this file:

artnftDropContractAddress ="<your-nft-drop-contract-address>";arttokenContractAddress ="<your-token-contract-address>";artStakingContractAddress ="<your staking contract address>";

Now let's create the same structure withuse addressandUse metamaskto ensure the user has their wallet connected before we attempt to retrieve information:

artInsert: NextPage =() =>{// Wallet connection hooks artAdresse = useAddress();artconnectWithMetamask = useMetamask();

Connect to all our contracts:

 // contract hook artnftDropContract = useNFTDrop(nftDropContractAddress);arttokenContract = useToken(tokenContractAddress);art{ contract, loading} = useContract(stakingContractAddress);

Use some helpful hooks to load:

  1. Balance this user has from this token
  2. The NFTs they have from this NFT collection:
 // Load the token's balance art{Data: tokenBalance } = useTokenBalance(tokenContract, address);// Load unstaked NFTs art{Data: ownNfts } = useOwnedNFTs (nftDropContract, Adresse);

You'll find that we use them.Phone callFunction to call one of the functions we wrote for the custom contract.

Load this user's staked NFTs if there is a connected wallet:

art[stakedNfts, setStakedNfts] = useState<any[]>([]);useEffect(() =>{if(!Contract)return;asynchronous function loadStakedNfts(){artstakedTokens =expectcontract?.call("getStakedTokens", address);// Get metadata for the NFT for each staked token artstakedNfts =expect Promise.all( stakedTokens?.map(asynchronous(stakedToken: {Calls: string; tokenId: BigNumber }) => {artnf =expectnftDropContract?.get(stakedToken.tokenId);returnnft; } ) ); setStakedNfts(stakedNfts);console.Protocol("setStakedNfts", stakedNfts); }if(address) { loadStakedNfts(); } }, [address, contract, nftDropContract]);

Reload the available rewards for this user.Phone call:

 art[claimableRewards, setClaimableRewards] = useState<BigNumber>(); useEffect(() =>{if(!contract || !address)return;asynchronous function loadClaimableRewards(){artcr =expectcontract?.call("Available Awards", address); setClaimableRewards(cr); } LoadClaimableRewards(); }, [address, contract]);

stake function call:

So that the contract comes aboutTransferOur NFTs must have themapprovalto.

Inside themissionFunction we check if the smart contract is approved and callsetApprovalForAllif it doesn't already have permission to transfer NFTs from that wallet for that collection.

 asynchronous function PfahlNft(ID: BigNumber){if(!address)return;artis approved =expectnftDropContract?.isApproved( Adresse, StakingContractAddress );// If not approved, request approval if(!is approved) {expectnftDropContract?.setApprovalForAll(stakingContractAddress,true); }artuse =expectcontract?.call("Mission", I would); }

revocation function with.Phone call:

 asynchronous function withdraw(ID: BigNumber){artwithdraw =expectcontract?.call("withdraw", I would); }

Claim Rewards feature with.Phone call:

 asynchronous function withdraw(ID: BigNumber){artwithdraw =expectcontract?.call("withdraw", I would); }

Now we can display all the information we've retrieved on the UI!

State of charge:

 if(charged) {return <div>Loading</div>; }

Show a button to connect the wallet if there isn't oneaddress:

return(<div class name={styles.container}> <h1 class name={style.h1}>Deploy your NFTs</h1> <Std class name={`${styles.dividers} ${styles.spacerOben}`} />{!address ? (<Knopf class name={styles.mainButton} onClick={connectWithMetamask}>connect wallet</Knopf>) : (<>// ... the next blocks of code go here</>)} </div> );

View the connected wallet's claimable rewards and token balance

<h2>Your tokens</h2><div class name={styles.tokenGrid}> <div class name={styles.tokenItem}> <h3 class name={styles.tokenLabel}>Claimable Rewards</h3> <p class name={styles.tokenValue}> <b>{!claimableRewards ? "Laden..." : ethers.utils.formatUnits(claimableRewards, 18)}</b>{" "} {tokenBalance?.symbol}</p> </div> <div class name={styles.tokenItem}> <h3 class name={styles.tokenLabel}>current balances</h3> <p class name={styles.tokenValue}> <b>{tokenBalance?.displayValue}</b>{tokenBalance?.symbol}</p> </div> </div>

Button for users to claim their available rewards:

<button class name={`${styles.mainButton} ${styles.spacerTop}`} onClick={() =>ClaimRewards()} > Claim Rewards </button>

Check out all of their staked NFTs:

Each mapped div contains onewithdrawbutton to call thewithdrawfunction and pass in the token ID of that element.

<h2>Your deployed NFTs</h2><div class name={styles.nftBoxGrid}>{stakedNfts?.map((nft) => (<div class name={styles.nftBox} key={nft.metadata.id.toString()}> <ThirdwebNftMedia metadata={nft.metadata} class name={styles.nftMedia}/> <h3>{nft.metadata.name}</h3> <Knopf class name={`${styles.mainButton} ${styles.spacerBottom}`}onClick={()=>retire(nft.metadata.id)} > Retire</Knopf> </div>))}</div>

Check out all of theirsobsessedNFTs (NFTs from this collection that are not stacked in the contract):

Each mapped div contains a button that the user can invokePfahlNftFunction that in turn passes the token ID as a parameter.

<h2>Your unused NFTs</h2><div class name={styles.nftBoxGrid}>{ownNfts?.map((nft) => (<div class name={styles.nftBox} key={nft.metadata.id.toString()}> <ThirdwebNftMedia metadata={nft.metadata} class name={styles.nftMedia}/> <h3>{nft.metadata.name}</h3> <Knopf class name={`${styles.mainButton} ${styles.spacerBottom}`}onClick={()=>stakeNft(nft.metadata.id)} > stake</Knopf> </div>))}</div>

You will also find that we use theThirdwebNftMediaComponent that renders the media object of the NFT differently depending on what kind of file type the NFT resolves.

That's it! Now users can see all the NFTs they have claimed from the/Mintroute, click themissionbutton and start earning rewards!

Give some money to the staking contract

One last thing, we need to give the NFT staking contract some of our tokens so they can distribute them as rewards.

We can do this via the Thirdweb CLI by going to our token contract and clicking theTransferKnopf:

Build an NFT Staking Smart Contract with Solidity &amp; Thirdweb Deploy! (26)

Then paste the address of your staking contract and send it some tokens!

Build an NFT Staking Smart Contract with Solidity &amp; Thirdweb Deploy! (27)

Now it's able to transfer tokens when someone tries to call youaccept rewardFunction!

πŸ₯³πŸŽ‰

(Video) Build A Mutation NFT Smart Contract (MAYC CLONE) in Solidity!πŸ”₯🦍 (thirdweb, hardhat, next.js)

In this guide, we've created three smart contracts and combined them together to create a project that rewards users for holding the NFTs.

We have created all this:

  • ERC-721 NFT Drop Contract
  • ERC-20 token contract
  • An NFT staking contract that rewards players with ERC-20 tokens

Disclaimer:This staking contract has not been audited and should not be used for production environments! Please do your own research and use it at your own risk.

Videos

1. Getting Started with Web3 Development - Deploy your First Smart Contract
(thirdweb)
2. LearnWeb3 Build an NFT Staking GameFi Contract
(ETHGlobal)
3. 6. Build a Staking Application in 1 Hour | Road to Web3
(Alchemy)
4. NFT ERC721 Staking Smart Contract With ERC20 Token Rewards - Part1 Introduction
(net2dev)
5. Minting/Staking NFTs Dapp (ThirdWeb Smart Contracts)
(Ahmed B)
6. Create an ERC721 NFT drop using thirdweb
(HashLips NFT)
Top Articles
Latest Posts
Article information

Author: Terence Hammes MD

Last Updated: 04/29/2023

Views: 6080

Rating: 4.9 / 5 (49 voted)

Reviews: 80% of readers found this page helpful

Author information

Name: Terence Hammes MD

Birthday: 1992-04-11

Address: Suite 408 9446 Mercy Mews, West Roxie, CT 04904

Phone: +50312511349175

Job: Product Consulting Liaison

Hobby: Jogging, Motor sports, Nordic skating, Jigsaw puzzles, Bird watching, Nordic skating, Sculpting

Introduction: My name is Terence Hammes MD, I am a inexpensive, energetic, jolly, faithful, cheerful, proud, rich person who loves writing and wants to share my knowledge and understanding with you.