Create a contract and web app that mints NFTs
This tutorial covers how to set up a decentralized web application (dApp) that allows users to create NFTs on Tezos. No prior knowledge of NFTs or Tezos is required, but because the tutorial application uses TypeScript, some familiarity with JavaScript or TypeScript makes it easier to understand.
In this tutorial, you will learn:
- What NFTs are
- How to set up distributed storage for NFT metadata
- How to deploy (originate) a smart contract to Tezos
- How to use the Taquito JavaScript/TypeScript SDK to access Tezos and user wallets and to send transactions to Tezos
This tutorial covers both the backend and frontend parts of a dApp. For a simpler tutorial that covers creating only the frontend application, see Mint NFTs from a web app.
What is a non-fungible token (NFT)?
An NFT is a special type of blockchain token that represents something unique. Fungible tokens such as XTZ and real-world currencies like dollars and euros are interchangeable; each one is the same as every other. By contrast, each NFT is unique and not interchangeable. NFTs can represent ownership over digital or physical assets like virtual collectibles or unique artwork, or anything that you want them to represent.
Like other types of Tezos tokens, a collection of NFTs is managed by a smart contract. The smart contract defines what information is in each token and how the tokens behave, such as what happens when a user transfers an NFT to another user. It also keeps a ledger that records which account owns each NFT.
In this tutorial, you create NFTs that comply with the FA2 standard (formally known as the TZIP-12 standard), the current standard for tokens on Tezos. The FA2 standard creates a framework for how tokens behave on Tezos, including fungible, non-fungible, and other types of tokens. It provides a standard API to transfer tokens, check token balances, manage operators (addresses that are permitted to transfer tokens on behalf of the token owner), and manage token metadata.
Tutorial application
The application that you set up in this tutorial has three parts:
- The smart contract runs on the Tezos blockchain to manage the NFTs, including creating, transferring, and destroying them
- The backend application runs on a web server to upload the NFT data to the internet
- The frontend application runs on a web server and allows the user to connect their wallet, enter the information for the NFT, and send a request to the smart contract to create the NFT
This diagram shows what happens when the user creates an NFT with the application. The rest of this tutorial covers these steps in detail:
The frontend application looks like this, with fields for the image to represent the NFT and for its metadata:
Prerequisites
To run this tutorial you need Node.JS and NPM installed. See https://nodejs.org/. You can verify that they are installed by running these commands:
node --version
npm --version
Configure IPFS storage
NFTs have metadata, usually including at least a title and description. Optionally, the NFT can include many other metadata fields, such as links to media and attributes in many different formats.
Because storage space on blockchains is expensive, developers don't put entire token metadata files on Tezos. Instead, they configure decentralized storage for the NFT data and put only the link to that data on Tezos itself. In this section, you set up storage for the NFT metadata using the InterPlanetary File System (IPFS) protocol.
IPFS requires authentication just like blockchain transactions, so in this section you set up an account with the Pinata IPFS provider and use it to upload (or pin) the NFT data to IPFS.
-
Create a free Pinata account at https://app.pinata.cloud/developers/api-keys.
-
Go to the API Keys tab and click New Key.
-
On the Create New API Key page, expand API Endpoint Access > Pinning and enable the
pinFileToIPFS
andpinJSONToIPFS
permissions, as in this picture: -
In the Key Name field, give the key a name, such as "My Key."
-
Click Create Key.
The API Key Info window shows the API key and secret, which you must copy immediately, because they are not shown again.
-
Copy the API Key and API Secret fields and save the values on your computer. You need these values in the next section.
You can see the new API key on the API Keys tab:
Now your applications can use your Pinata account to pin NFT data to IPFS.
Download the tutorial files
The tutorial application has three parts:
- The smart contract that manages the NFTs
- The backend application that handles uploading data to IPFS
- The frontend application that connects to the user's wallet, sends the data to the backend application, and sends the transactions to the smart contract to mint the NFTs
The tutorial application files are in this GiHub repository: https://github.com/trilitech/tutorial-applications/tree/main/nft-taquito.
If you have the git
program installed, you can clone the repository with this command:
git clone https://github.com/trilitech/tutorial-applications.git
If you don't have git installed, go to https://github.com/trilitech/tutorial-applications/tree/main/nft-taquito and click "Code Download ZIP" and extra the ZIP file on your computer.
Then, go to the application in the nft-taquito
folder.
The tutorial contract
The file contract/NFTS_contract.mligo
contains the code for the smart contract that manages the NFTs.
This contract is written in the CameLIGO version of the LIGO smart contract programming language, with a syntax similar to OCaml.
This contract is already written for you, so do not need any experience with these languages to run the tutorial.
This contract creates NFTs that comply with the FA2 standard (formally known as the TZIP-12 standard), the current standard for tokens on Tezos. The FA2 standard creates a framework for how tokens behave on Tezos, including fungible, non-fungible, and other types of tokens. It provides a standard API to transfer tokens, check token balances, manage operators (addresses that are permitted to transfer tokens on behalf of the token owner), and manage token metadata.
The full details of the smart contract are beyond the scope of this tutorial, but the major parts of the contract have descriptions in comments.
Contract entrypoints
Like APIs, smart contracts have entrypoints, which are commands that transaction senders (client applications such as your web app or other contracts) can call. To comply with the TZIP-12 standard, the smart contract must have these entrypoints:
transfer
: Transfers tokens from one account to anotherbalance_of
: Provides information about the tokens that an account ownsupdate_operators
: Changes the accounts that can transfer tokens
This contract includes these additional entrypoints:
mint
: Creates NFTsburn
: Destroys NFTs
Contract types
Because Tezos uses strongly-typed languages, this contract's code starts by defining the types that the contract uses. These types are important for verifying that data is in the correct format, such as the parameters the transaction senders pass.
For example, the transfer
entrypoint accepts a list of the transfer
type.
This type includes the account to transfer tokens from and a list of the transfer_destination
type, which includes the account to transfer tokens to, the ID of the token to transfer, and the amount to transfer:
type token_id = nat
type transfer_destination =
[@layout:comb]
{
to_ : address;
token_id : token_id;
amount : nat;
}
type transfer =
[@layout:comb]
{
from_ : address;
txs : transfer_destination list;
}
Error messages
The contract defines a series of error messages, and comments in the code describe what each error message means.
For example, the balance_of
and transfer
entrypoints return this error if the client requests information about a token that does not exist or tries to transfer a token that does not exist:
(** One of the specified `token_id`s is not defined within the FA2 contract *)
let fa2_token_undefined = "FA2_TOKEN_UNDEFINED"