I am involved in an NFT project where there is a policy locking date coming up, but I would like to give the option burn/lock/self-destruct the NFT through a smart contract (SC) at any time after that point, and create a new 'evolved' NFT to give to the holder.

Is this 'locking/burn' possible in Plutus?

I don't want to create a burn wallet as there are obvious security concerns there with private keys. So I think an SC is the only way to go.

I am rather new to plutus so any help is appreciated.

2 Answers 2


As @kindofdev points out, it is very simple to burn tokens with Plutus scripts. It is a little more involved if you want some kinda of side-effect/record of burning tokens. Still shouldn't be too difficult, although Plutus takes some time to learn.


There are no bounds on what can be sent to a Plutus Script, i.e. the script doesn't do any checks on new UTxOs at the address. This means you can't make the script do something just by sending something to it. The script only sees what is included in transactions spending the UTxOs at that address or minted from the address. It can see the entire transaction though, so multiple scripts can ensure something happens in other scripts atomically before validating.

Why does that matter?

You mention that you want to, for example, send an NFT to be replaced with an "evolved" NFT. You can definitely do this. In the simplest case, you can have your minting policy check that the old NFT is being burnt, at which point it will allow minting an "evolved" NFT.

Minting policies can't track any state though. They don't have a datum. So if you want to include any additional context for when tokens can be minted or evolved, that state must be stored on a separate validator script. This will require (at the very least) one validator script and one minting policy:

  1. A script for validating the burning of the original NFT
  2. A minting policy for minting the new "evolved" NFT

A transaction for evolving your NFT would spend a datum at Script #1 and replace it with a new datum (either identical or with some book-keeping data). The transaction would also mint the new NFT with Minting Policy #2.

The minting policy will only validate if the Script #1 Datum is spent in the transaction and the script will only validate if the old NFT is spent to the script and the new NFT is minted + any additional constraints you want to include.


You can have your "evolve" minting policy check if the pre-evolution NFT is being burned. If you need to include additional state/context for when that can happen, you can include that data on a separate, but inter-dependent, validator script.

Hope that helps. Might be worth looking at these other questions to give you more ideas:

How to lock funds in a smart contract?

Ensuring NFT collection uniqueness using counter as asset name?

Can a smart contract only be interacted with once

  • I think you could also use two minting policies. One for the "normal" token that will enable it to be burnt and one for the "special" token that will only mint it if the normal token is burnt, no script involved. Both policies would be "invoked" in the same transaction
    – Mateus
    Commented Mar 8, 2022 at 10:21
  • The problem I see is that neither scripts or policies have access to the tx metadata, where the NFT content is. This means the user could mint a special token with any characteristics he wanted (only constrained by the token name)
    – Mateus
    Commented Mar 8, 2022 at 10:23
  • One for the "normal" token that will enable it to be burnt and one for the "special" token that will only mint it if the normal token is burnt, no script involved Thanks. Good point. I'll note this. I think in many cases you'd want to follow the access token pattern to allow any bookkeeping, but there are cases where that is probably superfluous. WRT metadata. I'm actually unfamiliar with how metadata works. But I'm certain you can put whichever constraints you'd want by recording in the Validator Datum. They might not live on the token directly, but can still be recorded and read. Commented Mar 8, 2022 at 17:52

One option would be to define a validator which always fails and therefore, funds sitting at its address will be locked forever, ie, burned.

{-# INLINABLE mkValidator #-}
mkValidator :: () -> () -> ScriptContext -> Bool
mkValidator _ _ _ = False

Then, you can create a transaction which sends the NFT to the script address using mustPayToTheScript.

Hope this will be useful.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

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