1

I was fiddling with OpenZeppelin ERC721 contract and created my own contract inheriting from the ERC721.sol. I tried to change the _safeMint method, so I copied it from the parent contract and this require line was raising an error:

function _safeMint(address to, uint256 tokenId, bytes memory _data) internal virtual {
    // Some extra logic here while keeping the next line exactly as in the parent contract
    require(_checkOnERC721Received(address(0), to, tokenId, _data), "ERC721: transfer to non ERC721Receiver implementer");
}

Error:

contracts/nft.sol:98:17: DeclarationError: Undeclared identifier. 
require(_checkOnERC721Received(address(0), to, tokenId, _data), "ERC721: transfer to non ERC721Receiver implementer"); ^--------------------^

I believe this was due the _checkOnERC721Received was defined as private in the parent contract, and this made it unavailable to the child contract. So I decide to copy the _checkOnERC721Received method into my contract to solve the issue. However it raised another error:

contracts/nft.sol:114:5: TypeError: Overriding function is missing "override" specifier. 
function _checkOnERC721Received(address from, address to, uint256 tokenId, bytes memory _data) ^ (Relevant source part starts here and spans across multiple lines). 
https://github.com/OpenZeppelin/openzeppelin-contracts/blob/v3.4.0/contracts/token/ERC721/ERC721.sol:435:5: Overridden function is here: 
function _checkOnERC721Received(address from, address to, uint256 tokenId, bytes memory _data) ^ (Relevant source part starts here and spans across multiple lines).

And if I add the override param I now get:

https://github.com/OpenZeppelin/openzeppelin-contracts/blob/v3.4.0/contracts/token/ERC721/ERC721.sol:435:5: TypeError: Trying to override non-virtual function.
Did you forget to add "virtual"? function _checkOnERC721Received(address from, address to, uint256 tokenId, bytes memory _data) ^ (Relevant source part starts here and spans across multiple lines). 

contracts/nft.sol:114:5: Overriding function is here: 
function _checkOnERC721Received(address from, address to, uint256 tokenId, bytes memory _data) ^ (Relevant source part starts here and spans across multiple lines).

So it seems I can't override that method? How could I change the _safeMint logic in an child contract, while keeping this line https://github.com/OpenZeppelin/openzeppelin-contracts/blob/v3.4.0/contracts/token/ERC721/ERC721.sol#L318 ? Is the only way by creating the whole contract without inheritance?

The questions is for learning purposes, I'm not trying to do anything specific.

1 Answer 1

4

Two things you can do change _safeMint behavior

  • Override _safeMint and call its parrent

    contract MyToken is ERC721 {
        function _safeMint(address to, uint256 tokenId, bytes memory _data) internal override {
            /* Can do something here and modify input parameters */
            super._safeMint(to, tokenId, _data);
            /* Can do something else here */
        }
    }
    
  • Override _mint, in the current implementation _safeMint only calls _mint

    contract MyToken is ERC721 {
        function _mint(address to, uint256 tokenId) internal override {
            /* Can do something here and modify input parameters */
            super.mint(to, tokenId);
            /* Can do something else here */
        }
    }
    

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge that you have read and understand our privacy policy and code of conduct.

Not the answer you're looking for? Browse other questions tagged or ask your own question.