What I want to achieve is self-destructing token.

For example I'd like to have some updatable TTL value assigned to my token. If TTL is reached the token should be auto-burned.

What are the best possible solutions for such task?

Is such an implementation insecure? What are the good practices?


Interesting question, you are describing something similar to a time-based resource, like a ticket to an event or a calendar appointment, that has value before a certain deadline and becomes worthless afterwards (except as proof of attendance).

Your own token does not have to use the standard OpenZeppelin contracts for ERC20 or ERC721, but still meet the standard. What you defined as "burned" or "live" is up to your contract. In returning "ownerOf" or "balanceOf" you can simply do an additional check to see if the TTL is still valid.

contract TTL_ERC721 {

  mapping(uint256 => uint256) public deadBlockNumbers;


  function ownerOf(uint256 _tokenId) view public returns (address _owner) {
    if ((deadBlockNumber[_tokenId] == 0) || (block.number > deadBlockNumber[_tokenId])) {
      return "0x0000000000000000000000000000000000"; // check to make sure this is the correct number of zeros
    return owners[_tokenId];

  function mint(uint256 _tokenId, uint256 _owner, uint256 _blocksFromNow) public {
    // do some checks / requires here to make sure msg.sender is able to own this token
    owners[_tokenId] = _owner;
    deadBlockNumber[_tokenId] = _blocksFromNow;


Good luck, hope this helps.

| improve this answer | |
  • Yes, I know that such a thing might be achieved through modifying contract methods to check some stored TTL value. But it would be nice to be able to achive real token invalidation by maybe using another contract that would check for existing once and have feature to “burn” it. – Number16BusShelter Oct 2 '19 at 19:17
  • It would be nice, but the other contract would also need to have its method called, so ultimately all tx's begin with an externally owned account (i.e. a user) You could mark tokens as expired in a Solidity array, and then allow users when they call transfer or transferFom to burn the marked tokens, and clear the array. – Paul Pham Oct 3 '19 at 11:25

It's not possible to make it auto-burnable because every action inside Ethereum blockchain requires transaction. In case of erc721 burn - you need to call specific burn function. Everything you can do is to add some identifier (status) for every unique token and create a public view function which returns status(active/expired for example) based on your TTL or other conditions - this will be calculated every time without transactions. Then you can use it as a mark and if you want - burn expired tokens manually or during some other smart contract invocations.

| improve this answer | |

ERC-721 includes this event emitting requirement:

    /// @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);

If your TTL requires a specific time/block number for burning then it will be impossible to do this in a standards compliant way. This is because if you need action to happen on block 12345 then anybody could create block 12345 and they might exclude your transaction (which would have to be initiated off chain).

But if you need this then don't follow the standard! You can implement the getters so that effectively all such tokens will be non-existent after the certain time because any queries about them will not return any information.

| improve this answer | |

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