Hi, I was thinking of a case where each uri is set upon mint.
The mint function takes in an amount to mint and a corresponding number of uri in an array.
Then as the tokenID is increased, the current tokenID is is set to the uri in the array.
User mints 2 items, token id of first item is 1 and second item is 2
The uri given as [uri1, uri2] is then assigned, 1-uri1 and 2 to uri2
When the tokenURI is called, with tokenID argument, instead of concatenating a base uri with tokenid, it returns the uri from the mapping perhaps.
(Id=> uri) token
TokenURI(1) returns
token[1] =uri1
I wonder if it’s possible with the current protocols in place for ERC721
This should be possible and relatively simple to put together. You should give this a try and write the mint function that you need, then share it here.
Take a look at Contracts Wizard and choose Mintable + URI Storage. You should change safeMint so it takes an array of URIs instead of a single one, and then inside the function add a for loop.
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.2;
import "@openzeppelin/contracts/token/ERC721/ERC721.sol";
import "@openzeppelin/contracts/token/ERC721/extensions/ERC721URIStorage.sol";
import "@openzeppelin/contracts/access/Ownable.sol";
import "@openzeppelin/contracts/utils/Counters.sol";
contract MyToken is ERC721, ERC721URIStorage, Ownable {
using Counters for Counters.Counter;
Counters.Counter private _tokenIdCounter;
uint256 _tokenId = 1;
constructor() ERC721("MyToken", "MTK") {}
function safeMint(address to, string[] memory uri) public onlyOwner {
for(uint8 i = 0; i<uri.length; i++){
_tokenId = _tokenIdCounter.current();
_tokenIdCounter.increment();
_safeMint(to, _tokenId);
_setTokenURI(_tokenId, uri[i]);
}
}
// The following functions are overrides required by Solidity.
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);
}
}
Thank you so much!
this works pretty well, although I tried to initialize the token id as one, so the counter starts from one but it doesn't work that way. Is there a way i can make it start counting from 1?
function bulkMint(address to, string[] memory uris)
public
onlyRole(MINTER_ROLE)
{
for (uint8 i = 0; i < uris.length; i++) {
safeMint(to, uris[i]);
}
}
function safeMint(address to, string memory uri)
public
onlyRole(MINTER_ROLE)
{
uint256 tokenId = _tokenIdCounter.current();
_tokenIdCounter.increment();
_safeMint(to, tokenId);
_setTokenURI(tokenId, uri);
}
Shouldn't the safeMint() be internal, if it only gets called by bulkMint?
(I'm a newbie, so don't take my words for the truth!)
Have you found an answer? I'm trying to mint more than one NFT in one contract (with a list of URIs like you) and trying to figure out how to get it done properly
In this case it doesn't seem to make a difference. There is no real downside to making it public, only minimal overhead to bytecode size and runtime cost.