Hey everyone, (or whoever should happen to find this thread)
I'm Rhyot, an electronic music artist and I suppose now 'new solidity developer'. I'm essentially writing a smart contract to mint a collection of music NFTs to deploy a set collection amount of .mp4 ERC721 tokens to the blockchain, each NFT with a unique name. Currently, I'm able to get most of what I need to happen to happen, though I'm lost as to actually naming the tokens with the mint function. In my case, I am minting each token from a singular .mp4 file and a singular metadata.json file. I've gotten the metadata baseURI to properly concatenate with the tokenIdString, and I roughly understand how to concat the tokenBaseName with the tokenIdString, but I'm not sure how to actually call a function that will name a minted NFT based on that string.
I've been learning with chatGPT (which frankly is a confused mess but understands most of the syntax and language that I do not), and building from OpenZeppelin Contract Wizard templates in Remix IDE. This is now only day 5 of my dev experience with solidity, so generally, I'm not upset with where I'm at so far, just needing to tap in for some help from a more experienced community.
Once I can get safeMint to do all the things I need it to do, then I'll build out an updated safeMintBatch to basically loop the function. I've currently disabled safeMintBatch within the contract, but you'll see it commented out and still residing therein.
I've included my contract code below. Thanks in advance for advice!
Contract Code
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.9;
import "@openzeppelin/contracts@4.8.0/token/ERC721/ERC721.sol";
import "@openzeppelin/contracts@4.8.0/token/ERC721/extensions/ERC721Enumerable.sol";
import "@openzeppelin/contracts@4.8.0/token/ERC721/extensions/ERC721URIStorage.sol";
import "@openzeppelin/contracts@4.8.0/access/Ownable.sol";
import "@openzeppelin/contracts@4.8.0/utils/Counters.sol";
//import "@openzeppelin/contracts@4.8.0/proxy/utils/Initializable.sol";
//import "@openzeppelin/contracts/utils/Strings.sol";
/// @custom:security-contact rhyot@rhyotmusic.com
contract RhyotGenesis is
// Initializable,
ERC721,
ERC721Enumerable,
ERC721URIStorage,
Ownable
{
using Counters for Counters.Counter;
using Strings for uint256;
Counters.Counter private _tokenIdCounter;
// Set the MaxSupply of NFTs that can be minted (Note: default _maxBatchSize will be equal to this value setting)
uint256 MaxSupply = 100;
// Set the base name for the NFTs to which the token ID will be concatenated during the mint call
string public constant tokenBaseName = "Rhyot - Genesis #";
uint256 private _maxBatchSize = MaxSupply;
bool private _safeMintBatch;
uint256 private _totalSupply;
/// Constructor
constructor() ERC721("RhyotGenesis", "RHYGEN") {
_tokenIdCounter.increment();
}
// Set the base URI for the collection to the metadata.json file in IPFS
function _baseURI() internal pure override returns (string memory) {
return "ipfs://Qmc9C6PywPykjLpPqEtbnAwMgtFVKYxEo3mS6baE3X4oFY/";
}
// Return the current value of MaxSupply
function getMaxSupply() public view returns (uint256) {
return MaxSupply;
}
// Return the current value of maxBatchSize
function getMaxBatchSize() public view returns (uint256) {
return _maxBatchSize;
}
// Return the current values of both MaxSupply and maxBatchSize in a single call
function getMaxValues() public view returns (uint256, uint256) {
return (_maxBatchSize, MaxSupply);
}
// Set Maximum Values for Batch Size and Supply
function setMaxValues(uint256 maxBatchSize, uint256 _MaxSupply) public onlyOwner
{
// Ensure that maxBatchSize is not negative
require(maxBatchSize >= 0, "Batch Size cannot be negative");
// Ensure that maxBatchSize is not greater than MaxSupply
require(maxBatchSize <= _MaxSupply, "Batch Size cannot be greater than Max Supply");
// Check if the values are being set to their current values
require(_maxBatchSize != maxBatchSize || MaxSupply != _MaxSupply, "Values are already set to their current values");
// Update the variables
_maxBatchSize = maxBatchSize;
MaxSupply = _MaxSupply;
}
// Returns the Token ID of the next NFT that will be minted
function getNextTokenId() public view returns (uint256) {
return _tokenIdCounter.current();
}
// Mint a single NFT
function safeMint(address to) public onlyOwner {
// disable safeMintBatch
_safeMintBatch = false;
// Check if the max supply has been reached
require(_totalSupply < MaxSupply, "Max Supply reached");
// Increment the total supply and the token ID counter
_totalSupply++;
uint256 tokenId = _tokenIdCounter.current();
_tokenIdCounter.increment();
// Convert the token ID to a string
string memory tokenIdString = tokenId.toString();
// Concatenate the `tokenBaseName` and `tokenIdString` using the `abi.encodePacked` function to create tokenFinalName
bytes memory tokenFinalName = abi.encode(tokenBaseName, tokenIdString);
// Use the `abi.decode` function to decode the concatenated string from `tokenFinalName`to `printFinalName`
string memory printFinalName = abi.decode(tokenFinalName, (string));
// Mint the NFT and set the token URI
_safeMint(to, tokenId);
_setTokenURI(tokenId, tokenIdString);
super._setName(printFinalName);
// re-enable safeMintBatch
_safeMintBatch = true;
}
/* THIS SECTION CURRENTLY DISABLED FOR REPAIRS TO SAFEMINT
// Mint a batch of NFTs
function safeMintBatch(address to, uint256 batchSize) public onlyOwner {
// Check if the batch size is greater than the maximum supply
require(batchSize <= MaxSupply, "Batch size cannot be greater than the maximum supply");
// Check if the batch size is greater than the maximum batch size
require(batchSize <= _maxBatchSize, "Batch size cannot be greater than the maximum batch size");
// Check if the total number of NFTs plus the batch size is greater than the maximum supply
require(_tokenIdCounter.current() + batchSize <= MaxSupply, "Minting this batch would exceed the maximum supply");
// Otherwise, loop through the batch size, incrementing the token ID each time
for (uint i = 0; i < batchSize; i++) {
// Increment the total supply
_totalSupply++;
// Get the current token ID and increment the counter
uint256 tokenId = _tokenIdCounter.current();
_tokenIdCounter.increment();
// Convert the token ID to a string
string memory tokenIdString = tokenId.toString();
// Set the base URI for the collection
string memory baseURI = _baseURI();
// Concatenate the `tokenName`, `baseURI`, and `tokenIdString` using the `abi.encodePacked` function
bytes memory data = abi.encodePacked(tokenName, baseURI, tokenIdString);
// Use the `abi.decode` function to decode the concatenated string from `data`
string memory fullUri = abi.decode(data, (string));
// Mint the NFT and set the token URI
_safeMint(to, tokenId);
_setTokenURI(tokenId, fullUri);
}
*/
// The following functions are overrides required by Solidity
function _beforeTokenTransfer(address from, address to, uint256 tokenId, uint256 batchSize)
internal
override(ERC721, ERC721Enumerable)
{
super._beforeTokenTransfer(from, to, tokenId, batchSize);
}
function _burn(uint256 tokenId) internal override(ERC721, ERC721URIStorage) {
super._burn(tokenId);
}
function tokenURI(uint256 tokenId)
public
view
override(ERC721, ERC721URIStorage)
returns (string memory)
{
return super.tokenURI(tokenId);
}
function supportsInterface(bytes4 interfaceId)
public
view
override(ERC721, ERC721Enumerable)
returns (bool)
{
return super.supportsInterface(interfaceId);
}
}
Environment
Using Remix IDE with 0.8.17 compiler.