// SPDX-License-Identifier: MIT pragma solidity ^0.8.21; import "@openzeppelin/contracts/token/ERC20/IERC20.sol"; import "@openzeppelin/contracts/token/ERC721/ERC721.sol"; import "@openzeppelin/contracts/access/Ownable.sol"; import "./NAVISToken.sol"; import "./NDEX.sol"; contract Reputation is ERC721, Ownable { using SafeMath for uint256; mapping(address => uint256) public userNFTCounts; mapping(address => uint256) public stakedNFTs; uint256 public nextTokenId = 1; uint256 public nftToNAVISRatio = 5; uint256 public reputationToNFTThreshold = 1000; uint256 public stakingRewardsPerBlock = 1; // Adjust the reward rate uint256 public totalStakingRewards; NDEX public ndex; // NDEX contract reference event NFTMinted(address indexed user, uint256 tokenId); event NFTConvertedToNAVIS(address indexed user, uint256 tokenId, uint256 navisAmount); event NFTStaked(address indexed user, uint256 tokenId); event NFTUnstaked(address indexed user, uint256 tokenId, uint256 stakingRewards); constructor( address _navisToken, address _ndex, string memory _name, string memory _symbol ) ERC721(_name, _symbol) { ndex = NDEX(_ndex); } function setNftToNAVISRatio(uint256 _ratio) external onlyOwner { nftToNAVISRatio = _ratio; } function setReputationToNFTThreshold(uint256 _threshold) external onlyOwner { reputationToNFTThreshold = _threshold; } function setStakingRewardsPerBlock(uint256 _rewardsPerBlock) external onlyOwner { stakingRewardsPerBlock = _rewardsPerBlock; } function claimReputationPoints() external { uint256 availablePoints = reputationToken.balanceOf(msg.sender); require(availablePoints > 0, "No reputation points to claim"); reputationToken.transferFrom(msg.sender, address(this), availablePoints); reputationScores[msg.sender] += availablePoints; // Convert reputation points to NAVIS uint256 navisAmount = navisToken.convertReputationToNAVIS(availablePoints); navisToken.mint(msg.sender, navisAmount); // Mint NFT for every reputationToNFTThreshold points uint256 nftCountToMint = availablePoints.div(reputationToNFTThreshold); for (uint256 i = 0; i < nftCountToMint; i++) { _mint(msg.sender, nextTokenId); userNFTCounts[msg.sender] += 1; emit NFTMinted(msg.sender, nextTokenId); nextTokenId++; } emit ReputationPointsClaimed(msg.sender, availablePoints); } function convertNFTToNAVIS(uint256 tokenId) external { require(_isApprovedOrOwner(msg.sender, tokenId), "Not approved or owner of the NFT"); require(_exists(tokenId), "Token does not exist"); // Calculate NAVIS amount based on the conversion ratio uint256 navisAmount = nftToNAVISRatio * 1e18; // Assuming 1e18 represents 1 NAVIS // Burn the NFT _burn(tokenId); userNFTCounts[msg.sender] -= 1; // Mint NAVIS to the user navisToken.mint(msg.sender, navisAmount); emit NFTConvertedToNAVIS(msg.sender, tokenId, navisAmount); } function stakeNFT(uint256 tokenId) external { require(_isApprovedOrOwner(msg.sender, tokenId), "Not approved or owner of the NFT"); require(_exists(tokenId), "Token does not exist"); // Stake the NFT stakedNFTs[msg.sender] = tokenId; emit NFTStaked(msg.sender, tokenId); } function unstakeNFT() external { uint256 tokenId = stakedNFTs[msg.sender]; require(tokenId != 0, "No NFT staked"); // Unstake the NFT stakedNFTs[msg.sender] = 0; // Calculate staking rewards uint256 stakingRewards = calculateStakingRewards(); totalStakingRewards -= stakingRewards; // Mint NAVIS rewards to the user navisToken.mint(msg.sender, stakingRewards); emit NFTUnstaked(msg.sender, tokenId, stakingRewards); } function _beforeTokenTransfer(address from, address to, uint256 tokenId) internal override { super._beforeTokenTransfer(from, to, tokenId); require(!paused(), "Token transfer while paused"); } function calculateStakingRewards() internal view returns (uint256) { uint256 stakingDuration = block.timestamp - ndex.lastStakingTimestamp(msg.sender); return stakingDuration.mul(stakingRewardsPerBlock); } }