I am asking this question regarding to the dev note above Transfer event in the ERC721 spesification / code.

/// @dev This emits when ownership of any NFT changes by any mechanism. /// This event emits when NFTs are created (from == 0) and destroyed /// (to == 0). Exception: during contract creation, any number of NFTs /// may be created and assigned without emitting Transfer. At the time of /// any transfer, the approved address for that NFT (if any) is reset to none. event Transfer(address indexed _from, address indexed _to, uint256 indexed _tokenId);

I am scratching my head for days because of this. How is this possible? Technically, I couldn't think of any solution to create "n" tokens and assign to a wallet address, without mapping token ids in a for loop in the mint function. Probably to achieve this, enumeration functions in the official implementations should be bypassed. But then how do the tokens exist in contract? Is there an example implementation regarding this? I searched everywhere but couldn't find anything. Being able to create "n" number of NFTs on contract creation (without emitting an event) would benefit me a lot; I am working on some experiments, so I am disregarding the events for now.


2 Answers 2


Well there is no "official" implementation of anything. There are just reference implementations, and you can implement it in any way you want, as long as you follow the ERC-721 standard.

Furthermore, it is questionable whether the ERC-721 standard can enforce the emitting of the Transfer event. Technically it can't enforce it - there's no way to check for sure whether contract X will always emit the event and whether it should be considered ERC-721. So the point of "is contract X an ERC-721 contract" is rather vague.

If you look at one reference implementation of the mint functionality at https://github.com/OpenZeppelin/openzeppelin-contracts/blob/master/contracts/token/ERC721/ERC721.sol#L333 you can see that it emits the Transfer event. So what you could do is simply copy that code and add it to your contract constructor without the Transfer event, with whatever parameters you want (even with a loop if you wish).

Or, even better, for your tests you probably don't care whether your contract is really ERC-721 compatible or not, so you can include only the functionality you need for your tests and nothing else.


For creating many NFTs such that doing it via a for loop would go well over the gas limit, you don't actually mint them. Instead you allocate them (sequentially) within a predefined lower and upper bound, and let the user 'mint' (buy) them one at a time. Any NFTs within this range can be considered as defacto 'owned' by a target address that you will set. Any 'buys' of NFTs within this range will now be owned by the buyer, who fronts the gas cost of 'minting' the NFT.

This does mean overriding the default implementation of ERC721 to handle lazy minting.

contract VirtualNFT {

    address ContractOwner = address(1111);
    uint256 NFTSupply = 100000;
    uint256 claimedNFTs;
    mapping (address => uint) internal _balances;
    mapping (uint => bool) internal _isBought;
    mapping (uint NFT => address) internal _owners;

    function balanceOf(address account) { 
        return (account == ContractOwner) ? (NFTSupply - claimedNFTs) : _balances[account];

    function ownerOf(uint256 NFT) returns (address owner) {
        return (_isBought[NFT]) ? _owners[NFT] : ContractOwner;

    function transfer(from, to, NFT) public {
        // transfer logic
        _isBought[NFT] = true;
        _owners[NFT] = to; 
        // etc


This should give you the general idea.

Your Answer

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

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