NFT Code Review: Burnables
February 20th, 2022

In this edition, we’re going to look at the code for one of our very own projects.

🔥 Burnables NFT 🔥

The premise of Burnables is that the owner of the token can burn their NFT at any time and get the mint price sent to their wallet. Essentially creating the first-ever refundable NFT.

All in a trustless manner on-chain.

It was a stealth drop that a Neo Tokyo member caught on Etherscan. One hour after drop, the whole project was minted out. But that’s a story for another time.

Let’s dive in 👇🧵

At the top, we have the variables.

We’ll touch on each where they’re used.

You can see this is a 999 piece collection with a 0.08 ETH mint price.

Jumping right into the fun stuff…

Almost every NFT contract has a way to send the ETH paid minting to the owner’s wallet.

Usually through a function named `withdraw()` or the PaymentSplitter.

Burnables does not have that. You can see there is still 45.92 ETH sitting in the contract.

Instead, there is a private function `_widthdraw` that cannot be accessed externally.

yes, “withdraw” is spelled wrong. Don’t copy/paste code from other contracts 😑

The only caller of the private withdraw function is this `burn` function.

`burn` is what makes this project unique.

It does four things.

  1. Requires that the sender owns the `_tokedId` they’re trying to burn.
  2. Transfers the token to the burn address 0x000000000000000000000000000000000000dEaD.
  3. Increments the `_burnedTracker` to keep track of the number of Burnables burnt.
  4. Sends the 0.08 ETH to the token holder who burned their NFT.

This is the only way to get ETH out of the contract.

Kinda cool, no?

Here are the methods for `totalSupply()`.

They’re both driven by the `_tokenIdTracker` which is used to keep track of the number of mints.

There was no need to have `_totalSupply()`.

Fun fact, `totalSupply()` is what drives the “Max Total Supply” on Etherscan.

We should have implemented this function to be Total Minted - Total Burned to get the true supply count.

Next, we have functions to get the `totalBurned()`.

Similar to `_totalSupply()`, there was no need to have the internal version `_totalBurned()`.

`price` is a helper function that calculates the total ETH needed to mint a certain count of tokens.

`_mintAnElement` is another helper function for `mint`.

It increments the count to track the number minted, mints the token, and emits the event CreateBurnable.

The `mint` function is fairly standard.

It validates the 999 limit is not breached, the 0.08 ETH is paid per token, and then mints the tokens.

I would make some minor tweaks to mint if we were to write it again.

  • Remove `address _to` and instead send the token to `msg.sender`.
  • Remove the `saleIsOpen` modifier because it’s redundant.
  • Rename this to “mintBatch” and create a separate “mint” function to mint a single token with the goal of cheaper gas for minting a single token.

Here is `setBaseURI`.

Yes, Burnables has the same vulnerability with its metadata as other popular NFTs 🤦‍♂️

If we wanted to, we could change the base URI and turn your flames into cute kittens or anything else we want to 😈

It goes without saying, but if we were to write this today, we would have done this differently.

Finally, we have our overridden version of `tokenURI`.

There was really no reason to do this because the original implementation of `tokenURI` does basically the same thing we’re doing here.

Concatenating the base URI with the token ID.

Here is the ERC721 implementation of `tokenURI` for reference.

Thanks for reading!

If you liked this write-up and want to read more of these, please give us a follow on Twitter @BurnableLabs!

Subscribe to Burnable Labs
Receive the latest updates directly to your inbox.
Verification
This entry has been permanently stored onchain and signed by its creator.
More from Burnable Labs

Skeleton

Skeleton

Skeleton