How to create a motherf*cking NFT using JavaScript
Tags: javascript, nft, web3, ethereum
Published: 2021-12-26 19:40:26

> _This blog post is outdated as it is based on V1. Please use thirdweb V2 for your upcoming projects._

In my previous [post](https://dev.to/abdulrauf11/how-to-create-a-motherfcking-nft-using-solidity-5b5d), I explained how you can mint an NFT using Solidity. But what if you don't want to learn Solidity? 

> _Ain't nobody got time for that b*tch._

You want to stick with your ol' pal JavaScript. Let me tell you that there's a way to do it. I present to you [thirdweb](https://thirdweb.com/portal) - a library of smart contracts, SDK, and UI components that developers can use in their app.
 
How cool would it be if you could just call a `mint` function, give the token's metadata as an argument, and it mints an NFT for you? All without writing a single line of Solidity code. Let's see if that's possible.

## Introduction to thirdweb
The first thing you need to learn about is the concept of `projects` and `modules`. In short, projects are smart contracts that act as containers for your modules. On the other hand, modules are packages that contain smart contracts and other functionalities. Head over to this [link](https://thirdweb.com/portal/learn/introduction) to learn more about them.

### All the steps we need to take
The following are the steps we need to take to mint our NFT:
1. Create a project using thirdweb
2. Deploy an NFT module inside our project
3. Mint our NFT

All of these steps will be done using just JavaScript. I will be separating these steps into 3 different `.js` files.


## Setup
Before we start writing the code, we need to create a `MetaMask` wallet. Since we'll be deploying our contracts on the `Rinkeby` network, we'll also need some testnet ETH to approve the transactions. [Here's a guide on how to create a MetaMask Wallet and get testnet ETH](https://thirdweb.com/portal/guides/create-a-metamask-wallet).

Now, head over to your thirdweb dashboard and create a project. Give it a name and a description of your choice. Make sure you've switched your network to Rinkeby.

![Create project - thirdweb dashboard](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/1cnx0gk0byz34q9z81nb.png)

We'll do everything else using code.
 
## The code

Go ahead and create an empty project and install all the necessary packages:

- **@3rdweb/sdk** - to use the smart contracts provided by thirdweb
- **ethers** - to connect our MetaMask wallet
- **dotenv** - to source sensitive data from a `.env` file

```shell
npm init -y
npm install @3rdweb/sdk ethers dotenv
```

Let's create 3 separate files to code all the steps I mentioned above.
```shell
touch 1-init-sdk.js 2-deploy-collection.js 3-mint-nft.js
```
### 1. Let's initialize the SDK
I like to show the entire code first before explaining it. Therefore, before further ado, here's the code for the first file i.e. `1-init-sdk.js`
```js
import { ThirdwebSDK } from '@3rdweb/sdk';
import ethers from 'ethers';

import dotenv from 'dotenv';
dotenv.config();

const sdk = new ThirdwebSDK(
  new ethers.Wallet(
    // Your wallet private key. ALWAYS KEEP THIS PRIVATE, DO NOT SHARE IT WITH ANYONE.
    // Add it to your .env file and do not commit that file to github!
    process.env.PRIVATE_KEY,
    // RPC URL, we'll use our Alchemy API URL from our .env file.
    ethers.getDefaultProvider('https://rinkeby-light.eth.linkpool.io/')
  )
);

(async () => {
  try {
    const apps = await sdk.getApps();
    console.log('Your app address is:', apps[0].address);
  } catch (err) {
    console.error('Failed to get apps from the sdk', err);
    process.exit(1);
  }
})();

// We are exporting the initialised thirdweb SDK so that we can use it in our other scripts
export default sdk;
```
The code is really simple. We're importing thirdweb and then initializing the SDK. We're exporting it at the end so we can re-use it in the next script.

We're also running this:
```js
(async () => {
  try {
    const apps = await sdk.getApps();
    // Get the address of the most recently created project
    console.log("Your app address is:", apps[0].address);
  } catch (err) {
    console.error("Failed to get apps from the sdk", err);
    process.exit(1);
  }
})(
```
This code returns the address of your app or project. It's the address of the container that will hold all your modules. Remember, we created a project using our dashboard in the beginning? This will return its address.

Go ahead and run the following command in your terminal:
```shell
node 1-init-sdk.js
```
Here's what I get when I run the script:
```bash
lilcoderman % node scripts/1-init-sdk.js
Your app address is: 0x25320e23DCd1813D11787aD836865a64CC69897A
```

### 2. Deploying the NFT module
Now that we have our project/app, let's use the `deployNftModule` provided by thirdweb to deploy our collection. It is one of the methods available to the SDK we initialized in the first step.

We're not creating our NFT here, yet. This module will only help us create + deploy an ERC-721 collection to the Rinkeby testnet. We're just setting up the metadata of the collection itself. You know stuff like the name (e.g. Bored Ape Yacht Club), description, and image associated with the entire collection.

Go ahead and copy the following code to the `2-deploy-collection.js` file:

```js
import sdk from './1-init-sdk.js';
import { readFileSync } from 'fs';

import dotenv from 'dotenv';
dotenv.config();

const app = sdk.getAppModule('YOUR_APP_ADDRESS');

(async () => {
  try {
    const nftModule = await app.deployNftModule({
      // The collection's name, ex. CryptoPunks
      name: 'JavaScript NFTS',
      // A description for the collection.
      description:
        'How to mint an NFT using Javascript - a tutorial by @lilcoderman',
      // The image for the collection that will show up on OpenSea.
      image: readFileSync('assets/collection.png'),
      // The amount of royalty collected on all royalties represented as basis points. The default is 0 (no royalties).
      // 1 basis point = 0.01%
      // For example: if this value is 100, then the royalty is 1% of the total sales.
      sellerFeeBasisPoints: 0,
      // The address of the royalty recipient. All royalties will be sent to this address.
      feeRecipient: process.env.WALLET_ADDRESS,
      // The symbol for the NFT Collection
      symbol: 'JS',
    });

    console.log(
      '✅ Successfully deployed nft module, address:',
      nftModule.address
    );
  } catch (error) {
    console.log('failed to deploy nft module', error);
  }
})();
```
The code is pretty self-explanatory. We're importing our SDK from the previous file and calling one of its methods. This method will deploy an NFT module (i.e collection) for us. We've also provided the necessary metadata as an argument to the `deployNftModule` function.

Once you run this script, it will return the collection's address. Here's what I get:

```bash
lilcoderman % node scripts/2-deploy-collection.js
✅ Successfully deployed nft module, address: 0x1C267DC8841999de9B9C4F33D63a8d6bC81b8e2D
```

### 3. Time to mint our NFT
We're almost done now! It's time to mint our NFT, and we haven't even written a single line of Solidity. This is probably the simplest code we've written so far. Copy the following code to the final file `3-mint-nft.js`:

```js
import sdk from './1-init-sdk.js';
import { readFileSync } from 'fs';

const nft = sdk.getNFTModule('YOUR_NFT_MODULE_ADDRESS');

(async () => {
  try {
    await nft.mint({
      name: 'LCM',
      description: 'Follow me on twitter @lilcoderman',
      image: readFileSync('assets/nft.png'),
      properties: {},
    });
    console.log('✅ Successfully created a new NFT in the collection!');
  } catch (error) {
    console.error('failed to create the new NFT', error);
  }
})();
```
Just like before, we're importing the SDK from the first file. However, we are using the module `getNFTModule` this time around. This module returns our ERC-721 contract.

Then, we can call the `mint` function from the contract to create an actual NFT! The mint function requires an object containing the metadata of the token. I've passed in the NFT's name, description, and image as arguments. You can also set its properties if you'd like.

Now, let's run it:
```bash
lilcoderman % node scripts/3-mint-nft.js
✅ Successfully created a new NFT in the collection!
```

You can now view the NFT on your thirdweb [dashboard](https://thirdweb.com/rinkeby/).

![NFT collection - thirdweb dashboard](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/4radw9vks53jstm2efdu.png)

We can also find our NFT on **OpenSea** by using its address. Go to this [link](https://testnets.opensea.io/assets/0x1c267dc8841999de9b9c4f33d63a8d6bc81b8e2d/0) to check mine.

That's it. You've now minted an NFT using JavaScript only. Pretty f*cking cool, won't you say?

Anyway, here's the Github repo with all the code: https://github.com/abdulrauf11/tutorial-thirdweb-nft

## What next...
thirdweb can do much more than just minting an NFT collection. It has modules for creating a custom token, a marketplace for NFTs, and even a DAO! In the future, they also plan to support other chains like Solana and Flow.

We're using JavaScript to do all the steps, however, it is not a requirement. You can do all this manually using your dashboard. In my opinion, doing it with code just gives you more flexibility.

Keep in mind, if you're going to use thirdweb in production, they will take a minor 5% cut from your royalties. I think that's fair given how they're making our lives much easier with their product.

<hr />
## Don't leave me, take me with you

Like what you read? Follow me on social media to know more about NFTs, Web development, and shit-posting.

Twitter: [@lilcoderman](https://twitter.com/lilcoderman)

Instagram: [@lilcoderman](https://www.instagram.com/lilcoderman/)