Search code examples
solidityopenzeppelinerc721

How to call _mint() on erc721 without emit Transfer


I've read here that it is possible to mint 2^256 nfts in a single transaction. I've tried to achieve this by directly assigning _owners and _balances mappings but ofc these are private variables so i can't change them. I tried making an _mint() override but that also didn't work. How does this process work?


Solution

  • For simplification, let's do a 10k NFTs scenario.

    It's not about invoking a single mint() function 10k times, rather than building your contract logic in a way that allows setting up a range of valid IDs.

    Using the MFS part of IPFS, you can upload multiple files into a folder using the same directory ID and actual file names. Example:

    https://ipfs.io/ipfs/<dir_id_abc>/1.json
    https://ipfs.io/ipfs/<dir_id_abc>/2.json
    https://ipfs.io/ipfs/<dir_id_abc>/3.json
    etc...
    

    These metadata files contain links to the images.

    Your contract can then implement a custom function that shadows an authorized address as an owner of the NFT if both following conditions are met:

    1. The ID is in a valid range (in our case 1-10k)
    2. The NFT is not owned by anybody else (i.e. it's owned by the default address 0x0)
    function _exists(uint256 tokenId) override internal view returns (bool) {
        if (tokenId >= 1 && tokenId <= 10000) {
            return true;
        }
    
        return super._exists(tokenId);
    }
    
    function ownerOf(uint256 tokenId) override public view returns (address) {
        address owner = _owners[tokenId];
    
        // The ID is in a valid range (in our case 1-10k)
        // The NFT is not owned by anybody else (i.e. it's owned by the default address 0x0)
        if (tokenId >= 1 && tokenId <= 10000 && owner == address(0x0)) {
            // shadows an authorized address as an owner
            return address(0x123);
        }
    
        return super.ownerOf(tokenId);
    }
    

    The tokenURI() function then validates the token existence (using the _exists() function) and returns the final URI concatenated from the base URI (https://ipfs.io/ipfs/<dir_id_abc>/), the ID, and the .json suffix.

    Mind that this approach does not work on the OpenZeppelin implementation, as their _owners property is private and not readable from child contracts. But you can take this snippet as an inspiration for a custom implementation that allows simulating an arbitrary default owner of 10k (or even 2^256) tokens.