Does preventing transfer under certain conditions violate ERC721?

I’m building a smart contract based on the ERC721PresetMinterPauserAutoId preset.

I want to prevent transfer of tokens under certain conditions which are known by the smart contract itself and accessible in the _beforeTokenTransfer function.

Would implementing such a guard violate the ERC721 standard? I read through the document here and it’s still not clear to me - https://eips.ethereum.org/EIPS/eip-721

Here’s what I’ve written:

    function _beforeTokenTransfer(address from, address to, uint256 tokenId) internal virtual override {
        require(address(0) == to || alive(tokenId - 1, now), "Dead tokens cannot be transferred");
        super._beforeTokenTransfer(from, to, tokenId);
    }

alive() returns a boolean, and i want to always allow burning.

1 Like

Hi @sbauch,

Welcome to the community :wave:

The EIP allows your implementation to throw in other situations, so this would be ERC721 compatible:

The transfer and accept functions’ documentation only specify conditions when the transaction MUST throw. Your implementation MAY also throw in other situations. This allows implementations to achieve interesting results:

  • Disallow transfers if the contract is paused — prior art, CryptoKitties deployed contract, line 611
  • Blacklist certain address from receiving NFTs — prior art, CryptoKitties deployed contract, lines 565, 566
  • Disallow unsafe transferstransferFrom throws unless _to equals msg.sender or countOf(_to) is non-zero or was non-zero previously (because such cases are safe)
  • Charge a fee to both parties of a transaction — require payment when calling approve with a non-zero _approved if it was previously the zero address, refund payment if calling approve with the zero address if it was previously a non-zero address, require payment when calling any transfer function, require transfer parameter _to to equal msg.sender , require transfer parameter _to to be the approved address for the NFT
  • Read only NFT registry — always throw from unsafeTransfer , transferFrom , approve and setApprovalForAll

I would recommend being very clear with your community under what circumstances a token cannot be transferred.

I assume you can't just use burning and need your own logic.

1 Like

Great thanks that makes a lot of sense.

I’m confused about your assumption though - poking through the preset code it looks like burn is a convenience method for a transfer to the null address, so I think the first part of the conditional is sufficient to use the burn function normally. It does seem to be working - I’m able to burn my dead tokens on rinkeby.

Oh and yeah absolutely hear you re: educating community. I’m building a game and making it very clear that the tokens must be kept alive and cannot be transferred if they die.

2 Likes