Create an NFT with Stacks
Tags: nft, stacks, clarity, clarinet
Published: 2022-11-18 07:21:42

Quickly create your own NFT using Clarity with Stacks.

![](https://i.imgur.com/AX325zW.jpg)

### **Hello Developers** 👋

Welcome to today’s post, where we’ll break down a blockchain topic into bite-sized pieces to help you learn and apply your new skills in the real world.

Today’s topic is *Creating an NFT with Stacks.*

Here’s a list of what we’ll cover 🗒

* ✅ Step 1: Set up your project using Clarinet
* ✅ Step 2: Configure dependencies and define traits
* ✅ Step 3: Create the NFT smart contract
* ✅ Step 4: Check the contracts for errors
* ✅ Step 5: Testing the contract on local chain
* ✅ Step 6: Deploy the NFT smart contracts

By the end of this post, you’ll be able to create and deploy your own NFT using the Stacks.

Let’s go! 🚀


### **Prerequisites**

There are some prerequisite that you should have setup before going into this tutorial ⚒️

1. You should have **Clarinet** installed on your system. [Follow the installation guide.](https://book.clarity-lang.org/ch01-01-installing-tools.html)
2. Setup your **Hiro wallet**. [Download the wallet.](https://wallet.hiro.so/)


### **✅ Step 1: Set up your project using Clarinet**

We will create a project called `music-bird` using Clarinet. Open up your terminal and type the following in the command:

```  
clarinet new music-bird
```
Once the project is created Open the folder in your favorite IDE (example: VS Code) and open the built-in terminal emulator by going to the Terminal menu and choosing New Terminal.

Now, Inside our project folder, we will create two new Clarity contracts using the following commands:

```
clarinet contract new nft-trait
```
```
clarinet contract new music-bird
```

Clarinet will create a boilerplate Clarity and test file, and add the contracts to the configuration file.

```
Creating file contracts/nft-trait.clar
Creating file tests/nft-trait_test.ts
```
```
Creating file contracts/music-bird.clar
Creating file tests/music-bird_test.ts
```

As we are not going to write any test cases in this post, so we can delete the `tests` folder.

### **✅ Step 2: Configure dependencies and define traits**

Now that we have the project setup out of the way, lets configure the dependencies and define the traits. 

For creating the NFT on stacks we need to follow the [Sip 009 NFT standard](https://github.com/stacksgov/sips/blob/main/sips/sip-009/sip-009-nft-standard.md) and its pre-defined traits. We will be writing our NFT contract based on this traits.

To assert that the `music-bird` NFT contract implements the trait of SIP-009, we can use the `impl-trait` function, as the NFT trait is already deployed on Stacks Mainnet, we can use that deployed contract address when deploying our NFT on mainnet but in this post we are deploying on testnet, so we will configure a NFT traits contract on our local. 

To do so, open up the `nft-trait.clar` file inside the `contracts` directory and add the following [traits](https://github.com/stacksgov/sips/blob/main/sips/sip-009/sip-009-nft-standard.md#trait) in it.

```
(define-trait nft-trait
  (
    ;; Last token ID, limited to uint range
    (get-last-token-id () (response uint uint))

    ;; URI for metadata associated with the token 
    (get-token-uri (uint) (response (optional (string-ascii 256)) uint))

     ;; Owner of a given token identifier
    (get-owner (uint) (response (optional principal) uint))

    ;; Transfer from the sender to a new principal
    (transfer (uint principal principal) (response bool uint))
  )
)
```

Now we have define the traits, lets configure the dependencies for our NFT smart contract. Open `Clarinet.toml` and edit the `[contracts.music-bird]` section, we need to add the dependency of `nft-trait` contract.

```
[contracts.music-bird]
path = "contracts/music-bird.clar"
depends_on = ["nft-trait"]
```

This will ensure that the `nft-traits` contract should deployed before our NFT smart contract as it depends on it.

### **✅ Step 3: Create the NFT smart contract**

Now everything is setup, let us jump into writing our NFT contract. Open the `music-bird.clar` contracts file and remove all the boilerplate code.

```
;; Use this when deploying on mainnet
;; (impl-trait 'SP2PABAF9FTAJYNFZH93XENAJ8FVY99RRM50D2JG9.nft-trait.nft-trait)
```
```
;; Use this when deploying on testnet
;; Implementing traits from the `nft-trait.clar` contract
(impl-trait .nft-trait.nft-trait)
```

By adding this expression, the analyzer will check if the contract implements the trait specified when the contract is deployed. It will reject the transaction if the contract is not a full implementation. It is therefore recommended to always use impl-trait because it prevent accidental non-conformity.

Now let's define a non fungible token which will take the name of the NFT and its identifier type, Since the SIP requires the asset identifier type to be an unsigned integer, we add our NFT definition next.

```  
(define-non-fungible-token music-bird uint)
```

The asset identifier for the NFT should be an incrementing unsigned integer. The easiest way to implement it is to increment a counter variable each time a new NFT is minted. Let us define a data variable for it.

```
(define-data-var last-token-id uint u0)
```

Now, we will add a constant for the contract deployer and two error codes. Here is everything put together:

```
;; Implementing traits from the `nft-trait.clar` contract
(impl-trait .nft-trait.nft-trait)

(define-constant contract-owner tx-sender)
(define-constant err-owner-only (err u100))
(define-constant err-not-token-owner (err u101))

(define-non-fungible-token music-bird uint)

(define-data-var last-token-id uint u0)
```
 
To get the token id of last minted NFT, we will define a read only function which will read the chain state and return us the value of `last-token-id` variable.
 
```
(define-read-only (get-last-token-id)
    (ok (var-get last-token-id))
)
```
 
After that, we will define one more read only function `get-token-uri` which is used to get metadata for the NFT. But in this post we are not going to look that, so we will keep it as none.

```
(define-read-only (get-token-uri (token-id uint))
    (ok none)
)
```

Now its time to define a public function to mint our NFTs which will take the `recipient` address and mint the NFT to that address.
 
```
(define-public (mint (recipient principal))
  (let
	(
	  (token-id (+ (var-get last-token-id) u1))
	)
	(asserts! (is-eq tx-sender contract-owner) err-owner-only)
	(try! (nft-mint? music-bird token-id recipient))
	(var-set last-token-id token-id)
	(ok token-id)
  )
)
```
In the above `mint` function,

- First, we have defined the local variable `token-id` and set its value by incrementing the `last-token-id` value with 1.
- After that, we have an `asserts!` function which will validate, is the transaction sender who is calling the mint function `tx-sender` is equal to the `contract-owner` who has deployed the contract or not. 
- With this check, the `mint` function can only be called by the contract owner, and not by anyone else.
- Then we are minting our `music-bird` NFT to the recipient.
- Once the NFT is successfully minted, we are updating the `last-token-id` variable with the updated value of `token-id` and returning the same.


Now let's define a read only function `get-owner` which will take the NFT's `token-id` and return the owner of the NFT.

```
(define-read-only (get-owner (token-id uint))
	(ok (nft-get-owner? music-bird token-id))
)
```

And, the final function in our contract will be a public function using which the NFT owner can transfer their NFT to some other address.

```
(define-public (transfer (token-id uint) (sender principal) (recipient principal))
    (begin
	(asserts! (is-eq tx-sender sender) err-not-token-owner)
	(nft-transfer? music-bird token-id sender recipient)
    )
)
```

In the above `transfer` function,
- It will take the NFT's token id, and the sender and recipient addresses.
- Then first we will check transaction sender address and the sender address received in parameter is same or not.
- If it is not same then we will throw an error that the transaction sender is not the owner of the NFT.
- And If the condition satisfies, we will begin to transfer the NFT of token id from the sender address to the recipient address.


### **✅ Step 4: Check the contracts for errors**

Now we have written our NFT contract and it's time to check for errors. Run the command on the terminal:

```
clarinet check
```


### **✅ Step 5: Testing the contract on local chain**

Once our code have been checked for errors we can now test our function by running them on local chain, which can easily be possible with clarinet. To do so we just need to run the following command on terminal

```
clarinet console
```

![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/unuer4x0ejcn629l4t0v.png)

Now our console session is running, lets call our `mint` function and try to mint a token for ourselves.

The syntax to call a contract from console in Clarinet is:

```
>> (contract-call? contract-identifier function-name param-1 param-2 ...)
```

So calling our mint function:
```
>> (contract-call? 'ST1PQHQKV0RJXZFY1DGX8MNSNYVE3VGZJSRTPGZGM.music-bird mint 'ST1PQHQKV0RJXZFY1DGX8MNSNYVE3VGZJSRTPGZGM)
```

![](https://i.imgur.com/ge8v97I.png)

You can see the NFT mint event and the resulting ok response. We can transfer the newly minted token with ID u1 to a different principal.

```
>> (contract-call? 'ST1PQHQKV0RJXZFY1DGX8MNSNYVE3VGZJSRTPGZGM.music-bird transfer u1 'ST1PQHQKV0RJXZFY1DGX8MNSNYVE3VGZJSRTPGZGM 'ST2CY5V39NHDPWSXMW9QDT3HC3GD6Q6XX4CFRK9AG)
```

![](https://i.imgur.com/xw2Sd00.png)

Here as well you can see the NFT transfer event and the resulting ok response. We can confirms that the token is now owned by the specified principal by calling the `get-owner` function.

```
>> (contract-call? 'ST1PQHQKV0RJXZFY1DGX8MNSNYVE3VGZJSRTPGZGM.music-bird get-owner u1)
```

![](https://i.imgur.com/S5pOP2F.png)


### **✅ Step 5: Deploy the NFT smart contracts**

To deploy our NFT smart contract on testnet, open up the [Sandbox - Stacks Explorer](https://explorer.stacks.co/sandbox/deploy?chain=testnet) 
* Connect your wallet and Switch to **testnet**.
* First we need to deploy our NFT trait smart contract
* Paste your NFT trait smart contract code in IDE and Update the contract name.

![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/m0uzx6rxfhzm76hhv44y.png)

* Click on **Deploy** and Confirm the transaction.

![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/p3hkwygyz4hdtf187nu5.png)

* You can view the transaction details in your wallet activity. Click on the transaction in you wallet activity and you will be redirected to Stacks block explorer page.

![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/mgn77za6tu0ti99qhjsw.png)


Now we will repeat the same steps for deploying our NFT smart contract, so first

* Copy and Paste your NFT smart contract code in IDE.
* Copy the contract name of `nft-trait` smart contract from the block explorer page and replace the path in `impl-trait` function in our NFT smart contract.

```
(impl-trait 'ST2K0T4HFQKJMMCHBYFPRNVBG0B1NZFZTV94RD9WE.nft-trait.nft-trait)
```

![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/nbxpxwq7d4sd0ci16gfk.png)


* Update the contract name, click on **Deploy** and Confirm the transaction.

![](https://i.imgur.com/MsV11N8.png)

* Similarly, you can view the transaction details in your wallet activity

![](https://i.imgur.com/FxegFnt.png)

* To view more details about the deployment, click on the transaction in you wallet activity.


![](https://i.imgur.com/0eirBMj.png)


That is all there is to it! NFTs in Clarity are really quite easy to do. The full source code of the project can be found here: https://github.com/0xShoaib/music-bird-nft