Need help modifying Solidity code to create custom NFTs with user input data and image selection

Hey everyone,

I am working on a Solidity contract that allows users to mint NFTs with custom information about agricultural batches (such as name, company information, variety, etc.) and an image that they can select themselves. However, I am currently stuck and need help to achieve this functionality. My current code only allows users to mint NFTs without any input of the custom information or image selection.

Here’s the existing code:

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

import “@openzeppelin/[email protected]/token/ERC721/ERC721.sol”;
import “@openzeppelin/[email protected]/token/ERC721/extensions/ERC721Enumerable.sol”;
import “@openzeppelin/[email protected]/security/Pausable.sol”;
import “@openzeppelin/[email protected]/access/Ownable.sol”;
import “@openzeppelin/[email protected]/utils/Counters.sol”;

contract Farmer is ERC721, ERC721Enumerable, Pausable, Ownable {

// ==== 1. Property Variables ==== //

using Counters for Counters.Counter;

Counters.Counter private _tokenIdCounter;

    // Struttura per contenere le informazioni del lotto agricolo
struct Batch {
    string Name;
    string CompanyInformation;
    string Variety;
    uint256 number;
    uint256 quantity;
    string certification;
    uint256 dateOfCreation;
    uint256 dateOfProduction;
}


uint256 public MINT_PRICE = 0.01 ether;
uint256 public MAX_SUPPLY = 500;

bool public publicMintOpen = false;
bool public allowListMintOpen = false;

mapping(address => bool) public allowList;

// ==== 2. Lifecycle Function ==== //

constructor() ERC721("Farmer", "FRM") {
    // Start token ID from 1.
    _tokenIdCounter.increment();
}

function withdraw() public onlyOwner(){
    require(address(this).balance > 0, "Balance is zero!" );
    payable(owner()).transfer(address(this).balance);
}

// ==== 3. Pauseable Functions ==== // 

function pause() public onlyOwner {
    _pause();
}

function unpause() public onlyOwner {
    _unpause();
}

// Function to modify the mint windows
function editMintWindows (
    bool _publicMintOpen,
    bool _allowListMintOpen
) external onlyOwner {
    publicMintOpen = _publicMintOpen;
    allowListMintOpen = _allowListMintOpen;
}

// Adding publicMint and allowListMint variables
// Require only the whitelisted addresses to MINT
function allowListMint() public payable{
    require(allowListMintOpen, "AllowList Mint is OVER!");
    require(allowList[msg.sender], "You are not eligible to mint!");
    require(msg.value == 0.001 ether, "Not enough ether sent!");
    internalMint();
}

// ==== 4. Minting Functions ==== //
// ==== 5. Make it payable ==== //
// ==== 6. Add a limited supply ==== //
function publicMint() public payable{
    require(publicMintOpen, "Public Mint OVER!");
    // Check if supply is minted out
    // Check that ether value is correct
    require(msg.value >= MINT_PRICE, "Not enough ether sent!");
    internalMint();
}

function internalMint() internal {
    require(totalSupply() < MAX_SUPPLY, "MINTING IS OVER!");
    uint256 tokenId = _tokenIdCounter.current();
    _tokenIdCounter.increment();
    _safeMint(msg.sender, tokenId);
}

// Function to get the balance of the contract
function withdraw(address _addr) external onlyOwner{
    uint256 balance = address(this).balance;
    payable(_addr).transfer(balance);
}

// Populating the AllowList
function setAllowList(address[] calldata addresses) external onlyOwner{
    for(uint256 i = 0; i < addresses.length; i++){
    allowList[addresses[i]] = true;
    }
}

// ==== 6. Other Function ==== // 
function _baseURI() internal pure override returns (string memory) {
    return "ipfs://FarmerBaseURI/";
}

function _beforeTokenTransfer(address from, address to, uint256 tokenId, uint256 batchSize)
    internal
    whenNotPaused
    override(ERC721, ERC721Enumerable)
{
    super._beforeTokenTransfer(from, to, tokenId, batchSize);
}

// The following functions are overrides required by Solidity.

function supportsInterface(bytes4 interfaceId)
    public
    view
    override(ERC721, ERC721Enumerable)
    returns (bool)
{
    return super.supportsInterface(interfaceId);
}

}

My goal is to have the user input the custom information (the properties in the “Batch” struct) and select an image when minting the NFT, which should then be visible in the NFT’s JSON metadata.

How can I modify the code to accept user input for the custom information and image selection while minting the NFT? Any help or guidance would be greatly appreciated!

Thanks!

Hi @Blu_Wathc

It seems you are already using the erc721 contract so you can use the mint function pass user token uri.
I guess no need to make any changes. You can use the built in erc721 functions.