Search code examples
soliditysmartcontractsremixethers.jshardhat

Is there a way to check how many times an ERC721 token has been minted?


I am using the OpenZeppelin's ERC721 Library, is there was a way to get the count of the number of times a token has been minted.

Is there a built-in mapping or function to check that?


Solution

  • You can use the Enumerable extension. The totalSupply() function returns the currently existing amount of tokens (minted minus burned), which in some cases might not the same thing as the total amount of minted tokens.

    pragma solidity ^0.8;
    
    import "@openzeppelin/contracts/token/ERC721/extensions/ERC721Enumerable.sol";
    import "@openzeppelin/contracts/token/ERC721/extensions/ERC721Burnable.sol";
    
    /*
     * `totalSupply()` (defined in ERC721Enumerable) returns 1
     * even though 2 tokens were minted, but 1 was also burned
     */
    contract MyCollection is ERC721Enumerable, ERC721Burnable {
        constructor() ERC721("CollectionName", "Symbol") {
            _mint(msg.sender, 1);
            _burn(1);
            _mint(msg.sender, 2);
        }
    
        // multiple parents define the same function
        // overriding here just to point at the expected parent class
        // related to the combination of `Burnable` and `Enumerable` in the same contract - not to `Enumerable` alone
        function _beforeTokenTransfer(address from, address to, uint256 tokenId) internal override(ERC721, ERC721Enumerable) {
            return ERC721Enumerable._beforeTokenTransfer(from, to, tokenId);
        }
    
        // same reason for overriding as above
        function supportsInterface(bytes4 interfaceId) public view override(ERC721, ERC721Enumerable) returns (bool) {
            return ERC721Enumerable.supportsInterface(interfaceId);
        }
    }
    

    Or you can override the _beforeTokenTransfer() hook and create a custom counter that takes into account only minting and ignores burning.

    pragma solidity ^0.8;
    
    import "@openzeppelin/contracts/token/ERC721/extensions/ERC721Enumerable.sol";
    import "@openzeppelin/contracts/token/ERC721/extensions/ERC721Burnable.sol";
    
    /*
     * `mintCounter` returns 2, ignores the burned tokens
     */
    contract MyCollection is ERC721Enumerable, ERC721Burnable {
        uint256 public mintCounter;
    
        constructor() ERC721("CollectionName", "Symbol") {
            _mint(msg.sender, 1);
            _burn(1);
            _mint(msg.sender, 2);
        }
    
        function _beforeTokenTransfer(address from, address to, uint256 tokenId) internal override(ERC721, ERC721Enumerable) {
            if (from == address(0)) {
                mintCounter++;
            }
    
            return ERC721Enumerable._beforeTokenTransfer(from, to, tokenId);
        }
    
        function supportsInterface(bytes4 interfaceId) public view override(ERC721, ERC721Enumerable) returns (bool) {
            return ERC721Enumerable.supportsInterface(interfaceId);
        }
    }