This project implements a staking mechanism for NFTs where users can stake their NFTs to earn ERC-20 reward tokens with additional features like pause/unpause, UUPS upgradeable and admin specific functions. The project consists of three main components:
- ERC-20 Token Contract: An ERC-20 token that will be used as the reward token for staking.
- NFT Contract: An ERC-721 contract that represents the NFTs that users can stake.
- Staking Contract: A contract that manages the staking, unstaking, and reward distribution processes for the NFTs.
-
ERC-20 Token Contract (
DZAPRewards
):- This contract implements an ERC-20 token with minting and burning functionalities. It includes a controller mechanism to allow only authorized addresses to mint and burn tokens.
-
NFT Contract (
DZAPNFT
):- This contract implements an ERC-721 token with minting capabilities. The contract owner can mint new NFTs.
-
Staking Contract (
NFTStaking
):- Users can stake their NFTs in this contract to earn ERC-20 reward tokens. The rewards are distributed per block based on the number of NFTs staked.
- The contract supports staking, unstaking with an unbonding period, and reward claiming with a delay period.
- It includes control mechanisms for pausing the contract and updating reward parameters.
-
Deploy ERC-20 Token Contract:
Deploy the
DZAPRewards
contract. This will be the reward token used for staking.npx hardhat run scripts/deployRewardToken.js --network <network_name>
-
Deploy NFT Contract with the Deployer's Address as the Owner:
Deploy the
DZAPNFT
contract with the deployer's address as the owner. This contract will represent the NFTs to be staked.npx hardhat run scripts/deployNFT.js --network <network_name>
-
Deploy Staking Contract with Token and NFT Address along with Other Details:
Deploy the
NFTStaking
contract with the addresses of the deployed ERC-20 token and NFT contracts, and other staking parameters such as reward per block, unbonding period, and reward claim delay.npx hardhat run scripts/deployStaking.js --network <network_name>
-
Mint NFTs to Your Address by Interacting with the NFT Contract:
Mint NFTs to your address using the
safeMint
function of theDZAPNFT
contract.npx hardhat console --network <network_name> > const nft = await ethers.getContractAt("DZAPNFT", "<nft_contract_address>"); > await nft.safeMint("<your_address>");
-
Use the
setApprovalForAll
Function to Provide Relevant Permissions:Use the
setApprovalForAll
function on theDZAPNFT
contract to allow the staking contract to manage your NFTs.npx hardhat console --network <network_name> > const nft = await ethers.getContractAt("DZAPNFT", "<nft_contract_address>"); > await nft.setApprovalForAll("<staking_contract_address>", true);
-
Approve the NFT Staking Contract for Minting and Sending Itself Reward Tokens by Adding It as a Controller:
Add the staking contract as a controller in the
DZAPRewards
contract to allow it to mint and transfer reward tokens.npx hardhat console --network <network_name> > const rewardToken = await ethers.getContractAt("DZAPRewards", "<reward_token_contract_address>"); > await rewardToken.addController("<staking_contract_address>");
-
Stake NFTs:
Stake your NFTs by calling the
stakeNFTs
function on the staking contract with the token IDs of the NFTs you want to stake.npx hardhat console --network <network_name> > const staking = await ethers.getContractAt("NFTStaking", "<staking_contract_address>"); > await staking.stakeNFTs([0, 1]); // Replace with your NFT token IDs
-
Unstake NFTs:
Unstake your NFTs by calling the
unstakeNFTs
function on the staking contract with the token IDs of the NFTs you want to unstake.npx hardhat console --network <network_name> > await staking.unstakeNFTs([0, 1]); // Replace with your NFT token IDs
-
Withdraw NFTs After Unbonding Period:
After the unbonding period has passed, withdraw your NFTs by calling the
withdrawNFTs
function on the staking contract with the token IDs of the NFTs you want to withdraw.npx hardhat console --network <network_name> > await staking.withdrawNFTs([0, 1]); // Replace with your NFT token IDs
-
Claim Rewards:
Claim your accumulated rewards by calling the
claimRewards
function on the staking contract.npx hardhat console --network <network_name> > await staking.claimRewards();
-
Update Reward Per Block:
The contract owner can update the reward per block using the
setRewardPerBlock
function.npx hardhat console --network <network_name> > const staking = await ethers.getContractAt("NFTStaking", "<staking_contract_address>"); > await staking.setRewardPerBlock(20); // Replace 20 with the desired reward per block
-
The contract owner can update the unbonding period using the
setUnbondingPeriod
function.npx hardhat console --network <network_name> > const staking = await ethers.getContractAt("NFTStaking", "<staking_contract_address>"); > await staking.setUnbondingPeriod(100); // Replace 100 with the desired unbonding period
-
The contract owner can update the reward claim delay using the
setRewardClaimDelay
function.npx hardhat console --network <network_name> > const staking = await ethers.getContractAt("NFTStaking", "<staking_contract_address>"); > await staking.setRewardClaimDelay(200); // Replace 200 with the desired reward claim delay
-
The contract owner can pause and unpause the staking contract using the
pause
andunpause
functions.npx hardhat console --network <network_name> > const staking = await ethers.getContractAt("NFTStaking", "<staking_contract_address>"); > await staking.pause(); > await staking.unpause();
-
Proper Approvals: Ensure that the staking contract has the necessary approvals to transfer NFTs and mint reward tokens. Users should grant approval to the staking contract to manage their NFTs using the
setApprovalForAll
function. -
Role Management: Only authorized addresses should be able to perform administrative functions such as updating parameters and pausing the contract. The contract owner should manage these roles and ensure that only trusted addresses are assigned administrative privileges.