I want to override the following inherited function:
function _setBaseURI(string memory baseURI) public override(ERC721Full, ERC721Metadata) {
_baseURI = baseURI;
}
The problem is that I get an error
Undeclared Identifier
with _baseURI
.
The variable was implemented private. Is it for that reason that it cannot be overwritten? And if so, why can the function be?
My contract:
pragma solidity ^0.6.0;
import "https://github.com/OpenZeppelin/openzeppelin-contracts/blob/v3.0.0-beta.0/contracts/token/ERC721/ERC721Full.sol";
import "https://github.com/OpenZeppelin/openzeppelin-contracts/blob/v3.0.0-beta.0/contracts/drafts/Counters.sol";
contract GameItem is ERC721Full {
using Counters for Counters.Counter;
Counters.Counter private _tokenIds;
constructor() ERC721Full("GameItem", "ITM") public {
}
function awardItem(address player, string memory tokenURI) public returns (uint256) {
_tokenIds.increment();
uint256 newItemId = _tokenIds.current();
_mint(player, newItemId);
_setTokenURI(newItemId, tokenURI);
return newItemId;
}
function _setBaseURI(string memory baseURI) public override(ERC721Full, ERC721Metadata) {
_baseURI = baseURI;
}
}
The Heritage
pragma solidity ^0.6.0;
import "../../GSN/Context.sol";
import "./ERC721.sol";
import "./IERC721Metadata.sol";
import "../../introspection/ERC165.sol";
contract ERC721Metadata is Context, ERC165, ERC721, IERC721Metadata {
// Token name
string private _name;
// Token symbol
string private _symbol;
// Base URI
string private _baseURI;
// Optional mapping for token URIs
mapping(uint256 => string) private _tokenURIs;
/*
* bytes4(keccak256('name()')) == 0x06fdde03
* bytes4(keccak256('symbol()')) == 0x95d89b41
* bytes4(keccak256('tokenURI(uint256)')) == 0xc87b56dd
*
* => 0x06fdde03 ^ 0x95d89b41 ^ 0xc87b56dd == 0x5b5e139f
*/
bytes4 private constant _INTERFACE_ID_ERC721_METADATA = 0x5b5e139f;
/**
* @dev Constructor function
*/
constructor (string memory name, string memory symbol) public {
_name = name;
_symbol = symbol;
// register the supported interfaces to conform to ERC721 via ERC165
_registerInterface(_INTERFACE_ID_ERC721_METADATA);
}
/**
* @dev Gets the token name.
* @return string representing the token name
*/
function name() external view override returns (string memory) {
return _name;
}
/**
* @dev Gets the token symbol.
* @return string representing the token symbol
*/
function symbol() external view override returns (string memory) {
return _symbol;
}
/**
* @dev Returns the URI for a given token ID. May return an empty string.
*
* If the token's URI is non-empty and a base URI was set (via
* {_setBaseURI}), it will be added to the token ID's URI as a prefix.
*
* Reverts if the token ID does not exist.
*/
function tokenURI(uint256 tokenId) external view override returns (string memory) {
require(_exists(tokenId), "ERC721Metadata: URI query for nonexistent token");
string memory _tokenURI = _tokenURIs[tokenId];
// Even if there is a base URI, it is only appended to non-empty token-specific URIs
if (bytes(_tokenURI).length == 0) {
return "";
} else {
// abi.encodePacked is being used to concatenate strings
return string(abi.encodePacked(_baseURI, _tokenURI));
}
}
/**
* @dev Internal function to set the token URI for a given token.
*
* Reverts if the token ID does not exist.
*
* TIP: if all token IDs share a prefix (e.g. if your URIs look like
* `http://api.myproject.com/token/<id>`), use {_setBaseURI} to store
* it and save gas.
*/
function _setTokenURI(uint256 tokenId, string memory _tokenURI) internal virtual {
require(_exists(tokenId), "ERC721Metadata: URI set of nonexistent token");
_tokenURIs[tokenId] = _tokenURI;
}
/**
* @dev Internal function to set the base URI for all token IDs. It is
* automatically added as a prefix to the value returned in {tokenURI}.
*
* _Available since v2.5.0._
*/
function _setBaseURI(string memory baseURI) internal virtual {
_baseURI = baseURI;
}
/**
* @dev Returns the base URI set via {_setBaseURI}. This will be
* automatically added as a prefix in {tokenURI} to each token's URI, when
* they are non-empty.
*
* _Available since v2.5.0._
*/
function baseURI() external view returns (string memory) {
return _baseURI;
}
function _beforeTokenTransfer(address from, address to, uint256 tokenId) internal virtual override {
super._beforeTokenTransfer(from, to, tokenId);
if (to == address(0)) { // When burning tokens
// Clear metadata (if any)
if (bytes(_tokenURIs[tokenId]).length != 0) {
delete _tokenURIs[tokenId];
}
}
}
}
It's a visibility issue.
If you want to access the _baseURI
property in a derived contract, you need to make it at least internal
(it's currently private
).
Which also means copying a set of contracts locally so that you can update the ERC721Metadata.sol
and import the updated version (and not the remote version) from the other contracts.
The _setBaseURI()
function alone can be overridden because it's visible from your contract.
Private functions and state variables are only visible for the contract they are defined in and not in derived contracts.
Cannot access private property in a derived contract.
Source of the quote: https://docs.soliditylang.org/en/v0.8.3/contracts.html#visibility-and-getters