Function _setTokenURI() in ERC721 is gone with pragma ^0.8.0

I have the same error, now it’s OK:

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

import "@openzeppelin/contracts/token/ERC721/extensions/ERC721URIStorage.sol";
import "@openzeppelin/contracts/utils/Counters.sol";

contract HarddiskCafe is ERC721URIStorage{
    using Counters for Counters.Counter;
    Counters.Counter private _tokenIds;
    mapping(string => uint8) hashes;
    
    constructor() ERC721("HarddiskCafe", "HDC") {}
  
    function awardItem(address recipient, string memory hash, string memory metadata) public returns (uint256){
        require(hashes[hash] != 1);
        hashes[hash] = 1;
        _tokenIds.increment();
        uint256 newItemId = _tokenIds.current();
        _mint(recipient, newItemId);
        _setTokenURI(newItemId, metadata);
        
        return newItemId;
    }
}
2 Likes

Hi @samshi,

You can try with the Contracts Wizard: https://zpl.in/wizard

1 Like

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.

Take a look at Contracts Wizard and select both URI Storage and Enumerable to see how you can combine them into one contract.

1 Like

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.

I've been compiling with and without _burn function. Compiler specifies the functions needed to override at error message.

Hey i'm trying to implement this code in my nft cause my NFT's are dynamically minted and i'd like to set the base URI myself but i'm getting this error instead

project:/contracts/DogeWars.sol:451:25: TypeError: Data location must be "calldata" for parameter in external function, but "memory" was given.
    function setBaseURI(string memory baseURI_) external onlyOwner() {
                        ^--------------------^

Hi Frangio, i'm using the contract wizard to implement the base uri function, but i'm getting this error, do i need to set the base uri directly in the ERC721 contract i'm inheriting from?

TypeError: Function has override specified but does not override anything.
   function _baseURI() internal pure override returns (string memory) {
                                     ^------^

Compilation failed. See above.

You seem to be using an older Solidity version and possibly an older OpenZeppelin Contracts version.

To implement the code in this thread, make sure you're using Solidity 0.8 and OpenZeppelin Contracts 4.x.

So similar issue and trying to follow the logic above, but have tried the multiple options given and all fail to compile, I would like to get whatever exentsions needed to import on my code to get that function call for _setTokenURI() to work. What is needed based on what you see?


You have imported ERC721URIStorage.sol but did not extend your contract with it.

You need to add contract AdvancedCollectible is ..., ERC721URIStorage.

Hi @abcoathup and @sjuanati I found your discussion useful.

I was wondering, does that mean that the use case for NOT using the ERC721URIStorage extension implies we can only have one go at storing a content on an IPFS directory using content addressing, because otherwise the URI would change?
I know we could use IPNS to point to a different URI, but that is not ideal as it would be controlled by a key pair, implying centralization and key management, which may be ok in some cases but not when minting NFTs.

Could you provide an example use case where somebody would just use the base implementation "as is", such as the ERC721PresetMinterPauserAutoId preset contract, without any extension? Wouldn't deploying a contract for every directory on IPFS be prohibitively expensive?
I understand this decision was taken to make the new base contract much cheaper, but then I'd find myself importing the extension anyway as it is needed for my use case, which is minting tokens dynamically.

Any thoughts would be greatly appreciated!

If you're minting tokens dynamically it's very reasonable to use ERC721URIStorage.