ParserError: Invalid token.
--> blockchain proj.sol:79:40:
|
79 | require(crops[tokenId].exists, “Crop does not exist”);
| ^

for the below code remove the above mentioned error and give me full code

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

import "@openzeppelin/contracts/token/ERC721/ERC721.sol";
import "@openzeppelin/contracts/access/Ownable.sol";
import "@openzeppelin/contracts/utils/math/SafeMath.sol";

contract FarmingCropNFT is ERC721, Ownable {
    using SafeMath for uint256;

    // Define events
    event CropIssued(uint256 cropID, string cropName, uint256 amount, uint256 value, address farmer);
    event CropTransferred(address from, address to, uint256 cropID, uint256 value);

    // Define struct for crop
    struct Crop {
        string cropName;
        uint256 amount;
        uint256 value;
        address farmer;
        bool exists;
        string ipfsHash; // added ipfsHash for off-chain data
    }

    // Define mapping of crop IDs to crops
    mapping(uint256 => Crop) public crops;

    // Define counter for crop IDs
    uint256 public cropIDCounter;

    // Define variable for mint price
    uint256 public mintPrice;

    // Define constructor to initialize contract and ERC721 token
    constructor() ERC721("Farming Crop NFT", "FARMCRP") {
        // Set the mint price
        mintPrice = 0.01 ether;
    }

    // Define function for farmer to issue NFT of crops to primary buyer
    function issueCropNFT(
        string memory _cropName,
        uint256 _amount,
        uint256 _value,
        string memory _ipfsHash
    ) public payable returns (uint256) {
        // Ensure minimum payment is met
        require(msg.value >= mintPrice, "Insufficient payment");

        // Increment crop ID counter
        cropIDCounter++;

        // Create new crop struct
        Crop memory newCrop = Crop({
            cropName: _cropName,
            amount: _amount,
            value: _value,
            farmer: msg.sender,
            exists: true,
            ipfsHash: _ipfsHash // store the ipfsHash for off-chain data
        });

        // Add new crop to mapping
        crops[cropIDCounter] = newCrop;

        // Mint NFT to farmer
        _mint(msg.sender, cropIDCounter);

        // Emit event for new crop issuance
        emit CropIssued(cropIDCounter, _cropName, _amount, _value, msg.sender);

        // Return crop ID
        return cropIDCounter;
    }

    // Override the transferFrom function with custom logic for primary and secondary buyers.
    function transferFrom(address from, address to, uint256 tokenId) public override {
        // Ensure crop exists
        require(crops[tokenId].exists, “Crop does not exist”);

        // If the owner is farmer, primary buyer logic
        if (ownerOf(tokenId) == crops[tokenId].farmer) {
            // Primary buyer logic
            // Here you can add conditions for primary buyer purchase
            super.transferFrom(from, to, tokenId);
            emit CropTransferred(from, to, tokenId, crops[tokenId].value);
        } else {
            // Secondary buyer logic
            // Here you can add conditions for secondary buyer purchase on the marketplace
            super.transferFrom(from, to, tokenId);
            emit CropTransferred(from, to, tokenId, crops[tokenId].value);
        }
    }

    // Define function for farmer to destroy NFT of crops when they stop farming
    function destroyCropNFT(uint256 _cropID) public onlyOwner {
        // Ensure crop exists and is owned by farmer
        require(crops[_cropID].exists, "Crop does not exist");
        require(ownerOf(_cropID) == crops[_cropID].farmer, "Crop is not owned by farmer");

        // Burn NFT
        _burn(_cropID);

        // Emit event for crop destruction
        emit CropTransferred(crops[_cropID].farmer, address(0), _cropID, crops[_cropID].value);

        // Delete crop from mapping
        delete crops[_cropID];
    }

    // Add a function to retrieve the IPFS hash
    function getCropIPFSHash(uint256 _cropID) public view returns (string memory) {
        require(crops[_cropID].exists, "Crop does not exist");

        return crops[_cropID].ipfsHash;
    }
}