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.
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 transfers — transferFrom 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.
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.