I see two use-cases in which _setTokenURI might be useful:
If we need to build the URI considering a different name than the sequential tokenId (for instance, adding category or group prefix before the tokenId, or even using identifiers such as UUID-like).
If we need to have different URIs per token type instead of having every token using the same baseURI (eg: using a path for hi-resolution pics and a different path for low-resolution pics associated with the NFT).
In summary, if the baseURI + '/' + tokenId is sufficient, I agree the current implementation should be fine. If this is not enough, then we either override function tokenURI() or use an extension if implemented.
If I import and derive ERC721URIStorage on that file I get multiple override errors. Where should I be importing and including ERC721URIStorage? Sorry, I’m pretty new to this.
I imagine you did something like contract ... is ERC721, ERC721URIStorage ?
This is good, but it will result in the override errors you mentioned. They can be worked around following the recommendations in the error message, but they’re pretty verbose. If you instead inherit ERC721URIStorage only (as in @sjuanati’s post above!) you will get all of ERC721 functionality without all the override errors.
It is never too early to start contributing to open source.
Updating documentation is a great way to start. My pitch is in: Solidity learning resources.
Thanks for the help! Sorry for the late reply. That cleared everything up It also helped me out on another issue and another contract. I’m not used to working in heavily OOP styled code. Thanks again!
I’m having trouble using ERC721URIStorage because I’m currently using ERC721Enumerable which both inherit from ERC721. Is there a way I can use both? It’d be great if you guys created an extension that implemented both of these into 1 file.
Hey @sjuanati thank you for sharing this. Could you tell me in your mint method, what is the tokenURI_ syntax? What get’s input here, the return of tokenURI method? Scott
I mixed the following features at wizard: URI storage, mintable and ownable. It gave me back:
'''
// 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";
contract PANA is ERC721, ERC721URIStorage, Ownable {
constructor() ERC721("PANA", "PANA") {}
function safeMint(address to, uint256 tokenId) public onlyOwner {
_safeMint(to, tokenId);
}
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);
}
} '''
My question is: why do we have _burn function? I see it returns super.TokenURI(tokenId) which executes the same function but from the contract that is inheriting. thanks beforehand.
This is an override that is required by Solidity even though it does nothing. Solidity basically requires you to explicitly say that you want the _burn implementation from your parent.