How to mint Cardano NFT using Smart Contract — Part II
Use case
In part I of this article, we’ve gone through how to build & run a Cardano smart contract (SC), send it some ADA and finally make a transaction to release the ADA stored.
Hope it gave you a basic idea on how the whole process works. The SC we developed before was rather useless as it doesn’t make any validation (release ADA whenever it’s called). We are now going to demo a more useful one, namely minting a non-fungible token (NFT).
Conditions of minting NFT
Actually, NFT can be minted before the launch of SC. At that time, we used a minting script that specifies the same token can’t be minted after certain timeslot. We’ve written an article on this back then. You can check it out here.
The disadvantage of this approach is that we have no idea if only 1 token is actually minted before the timeslot unless we check on blockchain explorer like Cardano Explorer and Cardano Scan.
With the introduction of SC (aka plutus script), it gives us another alternative to do this. The idea is to set the following 2 validations in the script:
- no of newly minted token == 1
- the input UTXO has to be equal to a specified value
The 1st one is easy to understand as by definition NFT can only has a quantity of 1. The 2nd one is using the trick that once a UXTO is spent, it can never be used again. Having both conditions met, we can ensure this NFT is truly unique in nature.
Plutus Script
We are using the examples from the Lobster challenge and Making NFTs with Plutus. Thanks to authors Lars Brünjes & Jonathan Fischoff for their open sources.
The core of the SC code is listed here:
The 1st validation is to check if UTXO equals to specified value
hasUTxO :: Bool
hasUTxO = any (\i -> txInInfoOutRef i == utxo) $ txInfoInputs info
the 2nd validation is to check if minted amount is 1
checkMintedAmount :: Bool
checkMintedAmount = case flattenValue (txInfoMint info) of [(_, tn', amt)] -> tn' == tn && amt == 1
_ -> False
Making a Minting Transaction
To get started, we have to download the source from github.
Then we need to generate a payment address
cardano-cli address key-gen \
--verification-key-file payment.vkey \
--signing-key-file payment.skey
cardano-cli stake-address key-gen \
--verification-key-file stake.vkey \
--signing-key-file stake.skey
cardano-cli address build \
--payment-verification-key-file payment.vkey \
--stake-verification-key-file stake.vkey \
--out-file payment.addr \
--testnet-magic 1097911063
Fund this payment address using the Testnet Faucet. We can query if it’s funded by
cardano-cli query utxo --address $(cat payment.addr) --testnet-magic 1097911063TxHash TxIx Amount--------------------------------------------------------------------------------------6c1160302bff7c84b347e6c9c1cf78cbafc8821efc730f6271589fcd848635f7 0 1000000000 lovelace + TxOutDatumHashNone
Note that this UTXO (6c1160302bff7c84b347e6c9c1cf78cbafc8821efc730f6271589fcd848635f7#0) is used as input for minting NFT
Start the nix-shell and build the Haskell program by
cabal build
If successful, we can proceed to run the program
cabal run create-nft-script -- PlutusScriptNFT 6c1160302bff7c84b347e6c9c1cf78cbafc8821efc730f6271589fcd848635f7#0
where 6c1160302bff7c84b347e6c9c1cf78cbafc8821efc730f6271589fcd848635f7#0 is the input UTXO and PlutusScriptNFT is the name of the NFT
the minting script will be generated ./scripts/nft-mint-policy.plutus
Finally, we can send the minting transaction by making use of the script
scripts/mint_nft.sh 6c1160302bff7c84b347e6c9c1cf78cbafc8821efc730f6271589fcd848635f7#0 $(cat ~/payment.addr) ~/payment.skey PlutusScriptNFT
Checking the Minted NFT
Finally, we can check if the NFT is successfully minted by querying the payment address (addr_test1qqtfm03wu070x9lv3vmnfe3q2cxms9ghfgeyk9zq8gv7xtfnp8pp5edacpzucxgsh7hzlvexm9jhettwkljkg5hufm7qq0dm52) on Cardano Scan
Challenges Ahead
As you can see above, we can make use of Cardano SC feature to mint an NFT that’s truly unique in nature. NFT minting is just one of the unlimited use cases of SC.
Another typical example is NFT’s Auction. We can send the NFT’s to SC. Bidders can send their ADA to SC and it can determine based on the programmed conditions (e.g highest bid within deadline) to release the NFT to the winner. In this way, both NFT owners and bidders don’t need to trust each other. Instead they only need to trust the SC which can be put on a public place (e.g. Github) to be verified by everybody. An excellent tutorial by Lars can be found here.
Besides, we can build Apps for Decentrailized Finance(Defi), Decentrailized Exchange (DEX), Gaming, Oracle, Stable Coins…, just to name a few.
However, as you may notice, we focus very much on the “on-chain” (validation happening in the blockchain) part of the SC feature, there is also a big “off-chain” part we haven’t focus on. For now, we just make sure of the command line interface (CLI) to create payment addresses & transactions, keep plutus scripts…... It would be to more convenient to have a solution that keeps the wallets, the complied SC and interface to interact with SC. That’s idea of having the Plutus Application Backend (PAB) which is an off-chain, backend service for managing and handling the requirements of the application instance throughout its lifecycle. Further reading can be found here. Certainly, the availability of PAB will speed up the rollout of Cardano Dapps. We will talk more about it when it’s ready for testing.