With an ERC721 Solidity contract
A non-fungible token (NFT) is a uniquely identifiable digital asset stored in a blockchain. Unlike cryptocurrencies, which are fungible, an NFT is unique.
The ownership of an NFT is registered in the blockchain and can be transferred by the owner, enabling the sale and exchange of NFTs.
NFTs typically refer to digital files (images, videos, or others), and the NFT’s market value is tied to the digital file it refers to.
So, if NFTs are valuable digital assets, why should I burn them?
One reason would be the hope to make an NFT of a specific collection more valuable by making it rarer. For example, someone who owns all ten NFTs of a soccer player figurine may decide to destroy all except one to increase the value of the remaining one.
But, more frequently, companies:
- offer owners the chance to burn their NFTs in exchange for physical products or an “upgraded” version of the NFT
- urge people to purchase NFTs of a drop rapidly by announcing that they would destroy all unsold NFTs after a specific date
- eliminate unsold or problematic NFTs
The weird thing is that the EIP-721 states:
“…destruction of NFTs (“burning”) is not included in the specification. Your contract may implement these by other means.”
OK, let’s discuss the burning feature!
We need to start from an ERC-721 implementation. The OpenZeppelin ERC721 is one of the most widely utilized implementations.
This is a snippet of the contract code:
As we can see, this implementation already provides an internal
_burn function. The function accepts the token id as the input and does the following:
- gets the NFT’s owner
- calls the
_beforeTokenTransferhook function (what a hook is will be clearer later)
- clears all approvals for the token
- decreases the owner balance
- emits the Transfer event
- calls the
So, the job is done?
Wait, something is missing!
The function does not check if the sender is authorized to operate on the token. Let’s do it ourselves!
For this purpose, we can use the
_beforeTokenTransfer hook function.
As stated in OpenZeppelin documentation:
“Hooks are simply functions that are called before or after some action takes place. They provide a centralized point to hook into and extend the original behavior.”
_beforeTokenTransfer hook is an internal virtual function intended to be called before any token transfer, including minting and burning, with these conditions:
- when both “from” and “to” are non-zero, we are in the token transfer case
- when “from” is the zero address, we are in the minting case
- when “to” is zero,
tokenIdis going to be burned
- “from” and “to” are never both zero
Following the OpenZeppelin Rules of Hooks, follows a
In row 33, we check that we are in the burning or transfer scenario (“from” is not the zero address).
Then, the only address allowed to transfer or burn an NFT must be its owner so, at row 34, we get the owner of
tokenId and “require” that it must equal to the sender of the transaction (
Then, the only thing to do is to add a public
burn function that calls the parent contract
All solidity code and tests can be found at: https://github.com/donpabblo/burnable-nft
If you are here, thank you for reading. I sincerely hope that this explanation was useful to you.